From e2a842eb1561e72118cc2dea645cc7c91ef4e3ab Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Fri, 27 Sep 2019 06:37:44 +0200 Subject: [PATCH 001/474] Initial commit --- LICENSE | 21 +++++++++++++++++++++ README.md | 1 + 2 files changed, 22 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..46da469 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Informatik-AG (NGL) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f684ac7 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# envoy-client \ No newline at end of file From 4c9c0bf3a0137aa44a31e6459876130d88b7fe49 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 28 Sep 2019 11:51:52 +0200 Subject: [PATCH 002/474] Added Maven project --- .classpath | 38 ++++++++++++++++++++++ .gitignore | 1 + .project | 23 +++++++++++++ .settings/org.eclipse.core.resources.prefs | 6 ++++ .settings/org.eclipse.jdt.core.prefs | 8 +++++ .settings/org.eclipse.m2e.core.prefs | 4 +++ pom.xml | 31 ++++++++++++++++++ src/main/java/envoy/EnvoyClient.java | 25 ++++++++++++++ 8 files changed, 136 insertions(+) create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 pom.xml create mode 100644 src/main/java/envoy/EnvoyClient.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..d2bc4e0 --- /dev/null +++ b/.classpath @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/.project b/.project new file mode 100644 index 0000000..cc0e903 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + envoy-client + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..04cfa2c --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..cb635b1 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..14b697b --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d04ce4b --- /dev/null +++ b/pom.xml @@ -0,0 +1,31 @@ + + 4.0.0 + + informatik-ag-ngl + envoy-client + 0.0.1-SNAPSHOT + + Envoy Client + https://github.com/informatik-ag-ngl/envoy-client + + + UTF-8 + UTF-8 + 1.8 + 1.8 + + + + + org.jboss.resteasy + resteasy-client + 4.1.1.Final + + + + + envoy-client + + \ No newline at end of file diff --git a/src/main/java/envoy/EnvoyClient.java b/src/main/java/envoy/EnvoyClient.java new file mode 100644 index 0000000..29a6cc0 --- /dev/null +++ b/src/main/java/envoy/EnvoyClient.java @@ -0,0 +1,25 @@ +package envoy; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; + +/** + * Project: envoy-client
+ * File: EnvoyClient.java
+ * Created: 28 Sep 2019
+ * Author: Kai S. K. Engelbart + */ +public class EnvoyClient { + + public static void main(String[] args) { + Client client = ClientBuilder.newClient(); + WebTarget target = client.target("http://localhost:8080/envoy-server/rest/hello?name=InformatikAGNGL"); + Response response = target.request().get(); + String value = response.readEntity(String.class); + response.close(); + + System.out.printf("Response form server: %s%n", value); + } +} From be7f47164cff45631a197222fef55ca4bc48c6ce Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 28 Sep 2019 14:18:59 +0200 Subject: [PATCH 003/474] Added dependency to envoy-common --- .project | 17 +++++++++++++++++ pom.xml | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/.project b/.project index cc0e903..36de16d 100644 --- a/.project +++ b/.project @@ -15,9 +15,26 @@ + + org.jboss.tools.jst.web.kb.kbbuilder + + + + + org.jboss.tools.cdi.core.cdibuilder + + + + + org.eclipse.wst.validation.validationbuilder + + + org.eclipse.jdt.core.javanature org.eclipse.m2e.core.maven2Nature + org.jboss.tools.jst.web.kb.kbnature + org.jboss.tools.cdi.core.cdinature diff --git a/pom.xml b/pom.xml index d04ce4b..271a900 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,11 @@ resteasy-client 4.1.1.Final + + informatik-ag-ngl + envoy-common + 0.0.1-SNAPSHOT + From e4e3e973a2df09bd4de09ed99dcbed23749464a0 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 28 Sep 2019 16:23:00 +0200 Subject: [PATCH 004/474] Added message sending request --- .project | 10 ++++---- pom.xml | 5 ++++ src/main/java/envoy/EnvoyClient.java | 36 ++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/.project b/.project index 36de16d..08d7599 100644 --- a/.project +++ b/.project @@ -10,11 +10,6 @@ - - org.eclipse.m2e.core.maven2Builder - - - org.jboss.tools.jst.web.kb.kbbuilder @@ -30,6 +25,11 @@ + + org.eclipse.m2e.core.maven2Builder + + + org.eclipse.jdt.core.javanature diff --git a/pom.xml b/pom.xml index 271a900..d688c37 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,11 @@ resteasy-client 4.1.1.Final + + org.jboss.resteasy + resteasy-jaxb-provider + 4.3.1.Final + informatik-ag-ngl envoy-common diff --git a/src/main/java/envoy/EnvoyClient.java b/src/main/java/envoy/EnvoyClient.java index 29a6cc0..1ba3dc1 100644 --- a/src/main/java/envoy/EnvoyClient.java +++ b/src/main/java/envoy/EnvoyClient.java @@ -1,9 +1,18 @@ package envoy; +import java.time.Instant; + import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; +import javax.xml.bind.JAXBException; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; + +import envoy.schema.Message; +import envoy.schema.ObjectFactory; /** * Project: envoy-client
@@ -13,13 +22,26 @@ import javax.ws.rs.core.Response; */ public class EnvoyClient { - public static void main(String[] args) { - Client client = ClientBuilder.newClient(); - WebTarget target = client.target("http://localhost:8080/envoy-server/rest/hello?name=InformatikAGNGL"); - Response response = target.request().get(); - String value = response.readEntity(String.class); - response.close(); + public static void main(String[] args) throws DatatypeConfigurationException, JAXBException { + ObjectFactory factory = new ObjectFactory(); - System.out.printf("Response form server: %s%n", value); + Message.MetaData metaData = factory.createMessageMetaData(); + metaData.setSender("Kai"); + metaData.setRecipient("Maxi"); + metaData.setState(false); + metaData.setDate(DatatypeFactory.newInstance().newXMLGregorianCalendar(Instant.now().toString())); + + Message.Content content = factory.createMessageContent(); + content.setType("text"); + content.setText("Hello, World"); + + Message message = factory.createMessage(); + message.setMetaData(metaData); + message.getContent().add(content); + + Client client = ClientBuilder.newClient(); + WebTarget target = client.target("http://localhost:8080/envoy-server/rest/message/send"); + Response response = target.request().post(Entity.entity(message, "application/xml")); + response.close(); } } From c082229ead9f9574eaedb60ba429f04088beb7db Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sun, 29 Sep 2019 18:53:47 +0200 Subject: [PATCH 005/474] Add files via upload --- src/main/java/envoy/client/EnvoyClient.java | 89 +++++++++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 108 ++++++++++++++++++ target/classes/META-INF/MANIFEST.MF | 5 + .../envoy-client/pom.properties | 7 ++ .../informatik-ag-ngl/envoy-client/pom.xml | 41 +++++++ .../classes/envoy/client/EnvoyClient$1.class | Bin 0 -> 784 bytes target/classes/envoy/client/EnvoyClient.class | Bin 0 -> 3564 bytes .../envoy/client/ui/ChatWindow$1.class | Bin 0 -> 1329 bytes .../classes/envoy/client/ui/ChatWindow.class | Bin 0 -> 2409 bytes 9 files changed, 250 insertions(+) create mode 100644 src/main/java/envoy/client/EnvoyClient.java create mode 100644 src/main/java/envoy/client/ui/ChatWindow.java create mode 100644 target/classes/META-INF/MANIFEST.MF create mode 100644 target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.properties create mode 100644 target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.xml create mode 100644 target/classes/envoy/client/EnvoyClient$1.class create mode 100644 target/classes/envoy/client/EnvoyClient.class create mode 100644 target/classes/envoy/client/ui/ChatWindow$1.class create mode 100644 target/classes/envoy/client/ui/ChatWindow.class diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java new file mode 100644 index 0000000..ecb58b2 --- /dev/null +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -0,0 +1,89 @@ +package envoy.client; + +import java.awt.EventQueue; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.time.Instant; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; +import javax.xml.bind.JAXBException; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; + +import envoy.client.ui.ChatWindow; +import envoy.schema.Message; +import envoy.schema.ObjectFactory; + +/** + * Project: envoy-client
+ * File: EnvoyClient.java
+ * Created: 28 Sep 2019
+ * Author: Kai S. K. Engelbart and Maximilian Käfer + */ + +public class EnvoyClient { + + public static String content1 = ""; + + + /** + * Calls Class ChatWidow + */ + public static void main(String[] args) throws DatatypeConfigurationException, JAXBException { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + ChatWindow frame = new ChatWindow(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * specifies data
+ * sends xml to server
+ * gets response from server (currently 204) + */ + public static void sendMessage() throws DatatypeConfigurationException, JAXBException { + + ObjectFactory factory = new ObjectFactory(); + + Message.MetaData metaData = factory.createMessageMetaData(); + metaData.setSender("Kai"); + metaData.setRecipient("Maxi"); + metaData.setState(false); + metaData.setDate(DatatypeFactory.newInstance().newXMLGregorianCalendar(Instant.now().toString())); + + Message.Content content = factory.createMessageContent(); + content.setType("text"); + content.setText(content1); + + Message message = factory.createMessage(); + message.setMetaData(metaData); + message.getContent().add(content); + + Client client = ClientBuilder.newClient(); + WebTarget target = client.target("http://localhost:8080/envoy-server/rest/message/send"); + Response response = target.request().post(Entity.entity(message, "application/xml")); + System.out.println("Response code: " + response.getStatus()); + response.close(); + + + + } + + /** + * sets content of xml to content from ChatWindow + */ + public void setContent (String content2) { + content1 = content2; + } + +} diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java new file mode 100644 index 0000000..dad7788 --- /dev/null +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -0,0 +1,108 @@ +package envoy.client.ui; + +import java.awt.BorderLayout; +import java.awt.EventQueue; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextPane; +import javax.swing.border.EmptyBorder; +import javax.xml.bind.JAXBException; +import javax.xml.datatype.DatatypeConfigurationException; + +import envoy.client.EnvoyClient; + +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import java.awt.GridBagConstraints; +import java.awt.Color; + +/** + * Project: envoy-client
+ * File: ChatWindow.java
+ * Created: 28 Sep 2019
+ * Author: Maximilian Käfer + */ + +public class ChatWindow extends JFrame { + + private JPanel contentPane; + EnvoyClient envoyClient = new EnvoyClient(); + + public ChatWindow() { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(100, 100, 600, 800); + contentPane = new JPanel(); + contentPane.setBackground(new Color(220, 220, 220)); + contentPane.setForeground(new Color(0, 0, 0)); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + GridBagLayout gbl_contentPane = new GridBagLayout(); + gbl_contentPane.columnWidths = new int[]{1, 1, 1}; + gbl_contentPane.rowHeights = new int[]{1, 1, 1}; + gbl_contentPane.columnWeights = new double[]{0.3, 1.0, 0.1}; + gbl_contentPane.rowWeights = new double[]{0.05, 1, 0.07}; + contentPane.setLayout(gbl_contentPane); + + + // Message enter field ---------------------------------------------------------------------------- + JTextArea messageEnterTextfield = new JTextArea(); + messageEnterTextfield.setLineWrap(true); + + GridBagConstraints gbc_moveSelectionMessageEnterTextfield = new GridBagConstraints(); + gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; + gbc_moveSelectionMessageEnterTextfield.gridx = 1; + gbc_moveSelectionMessageEnterTextfield.gridy = 2; + + //gbc_moveSelectionMessageEnterTextfield.gridwidth = 10; + + gbc_moveSelectionMessageEnterTextfield.insets = new Insets(10, 10, 10, 10); + + contentPane.add(messageEnterTextfield, gbc_moveSelectionMessageEnterTextfield); + + + // Post Button ----------------------------------------------------------------------------------- + JButton postButton = new JButton("Post"); + postButton.setForeground(new Color(255, 255, 255)); + postButton.setBackground(new Color(0, 100, 0)); + + GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); + + gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; + gbc_moveSelectionPostButton.gridx = 2; + gbc_moveSelectionPostButton.gridy = 2; + + gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); + + contentPane.add(postButton, gbc_moveSelectionPostButton); + + + postButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + try { + if(messageEnterTextfield.getText().isEmpty() == false) { + envoyClient.setContent(messageEnterTextfield.getText()); + envoyClient.sendMessage(); + } + + } catch (DatatypeConfigurationException | JAXBException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + } + }); + + + + + + } + +} diff --git a/target/classes/META-INF/MANIFEST.MF b/target/classes/META-INF/MANIFEST.MF new file mode 100644 index 0000000..aaa130c --- /dev/null +++ b/target/classes/META-INF/MANIFEST.MF @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +Built-By: Maxi +Build-Jdk: 12.0.1 +Created-By: Maven Integration for Eclipse + diff --git a/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.properties b/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.properties new file mode 100644 index 0000000..d1fda1a --- /dev/null +++ b/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.properties @@ -0,0 +1,7 @@ +#Generated by Maven Integration for Eclipse +#Sun Sep 29 16:49:31 CEST 2019 +m2e.projectLocation=C\:\\Users\\Maxi\\git\\envoy-client +m2e.projectName=envoy-client +groupId=informatik-ag-ngl +artifactId=envoy-client +version=0.0.1-SNAPSHOT diff --git a/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.xml b/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.xml new file mode 100644 index 0000000..d688c37 --- /dev/null +++ b/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.xml @@ -0,0 +1,41 @@ + + 4.0.0 + + informatik-ag-ngl + envoy-client + 0.0.1-SNAPSHOT + + Envoy Client + https://github.com/informatik-ag-ngl/envoy-client + + + UTF-8 + UTF-8 + 1.8 + 1.8 + + + + + org.jboss.resteasy + resteasy-client + 4.1.1.Final + + + org.jboss.resteasy + resteasy-jaxb-provider + 4.3.1.Final + + + informatik-ag-ngl + envoy-common + 0.0.1-SNAPSHOT + + + + + envoy-client + + \ No newline at end of file diff --git a/target/classes/envoy/client/EnvoyClient$1.class b/target/classes/envoy/client/EnvoyClient$1.class new file mode 100644 index 0000000000000000000000000000000000000000..e179dc4c53c39ceda3a0b8111b08a067de72070a GIT binary patch literal 784 zcmZ`%QE$^Q5dPeyP03QWcC@TxumKySs~|$+ZHSkuNJtqVIu!v=ZfaVO)Tt78uwTUU zUN#9NegHoTadsy*CKky#pZ(o;_ucu|@9#eWJVo0@fniOk!}KVO6DgDqyT<9*{nir~ z4#V;RKjdM;)hK*DI1sURQDUf_pT3gNm#L95T;bkd>luz*D$F3Jo` zkyPT)#E#k`bgH{fC(DDwc1LPtRm~y>ynv;)OJ=T)r@f$0nY-*Hv+n=2DIJ zgdV3u7Y`U#uj-MH04@`_8+=4$hOY4g)%T}ZiQ3KyZhS*I zYM)^B*v3@|-=yS*wP6bgD85C^J2byG>Ud`sAH zc4>Pg@N8!?!~K1<<=DYZ0&CJ8V*>U4?u2YYivXG-u+~5W8U-%T+KxP0DvV2S)EduA zWzNl6`7z70)pxwuxGyxOV+~RU)}e_8gDKk=xHh|*>-3_&VA+nqRq4A{`ly`J2WE4! z7}&1kYiJeNsUn#*XA60A!V0Wlt|-l0S?%6plwNQ+;%3+p#vum zR!Lk>FIRJN%T66_Na@&!%^EfdtPjDoW|)O(;(JF)mZX7CVT(YE&AgnGSu2p9z}4xh zn2whmN5Pc|p|-q9BC|drXd3aQGchcE-2?b5pWl#rZvC?ssst+4DirX1O;6~vKTv-tgt1|{g#dL>(;}{`L=}{T$bXihPzm+GP7UA5V1ZPqtN$T{c2X`76!wCV6n34#@qARkwtb`H`DCpBTW#BaK zVjMNhVy&s>BCv5aV#N~V)#p_!kh4tkJ+L%EYft@$AwjX3#P{NFcX@Sc^hAr+Gn8h6FWlc;htD>l#XF5*n_!7RN;md?P;_{4d zdVb|Xi0*=eB|FbTH1Jj2$I2wJqIH&X?98m0pvD|MAh3HX2#S5CnOEI?%JqZ3-W|O= z%n++?UwYHhGd<}CW+CcLrs`8I_&Ofa@Ss5Js$Lm*7>@`v2JCv0l0;FtInIZXzs%b~<-*^cd7Ik0;@ixh`=&S z)d`{{oh^H@{Z;1A9Ahs)G=xZaM-!xg2^ zIX2cY`BYjB+b-gYz;m(X_VBHHJ1 z!;(3jo4}3GVOE)J;mX#~~Iyu~x`dk@zcU^!{Mvg0Ij&^sJakjgRV%GwKI-Hot7yIg4 z>r?kH;A?g0YiMm)z@q})sVC?0?FD?FYmFE1qf0n{D)sY=c&W9qj91F|br~1Rctd^7 zF9kS+6dmnl7=2jFL2y0xp%wel&e?A}Zow`NMtgCPZ=B=!JA^~H6Nfp13~~e*!W@p^ zX=L#%j)edn4%7M+F5wTfyO#a`k9dpt?!pt<8 literal 0 HcmV?d00001 diff --git a/target/classes/envoy/client/ui/ChatWindow$1.class b/target/classes/envoy/client/ui/ChatWindow$1.class new file mode 100644 index 0000000000000000000000000000000000000000..9c7d5d4553243fde0abf0b0939b2592023cd0cce GIT binary patch literal 1329 zcmaJ>>rN9v7(LTg7Ro{^7eVBzMcaZbRRj^dlu}gEstE)Y6XUQQU~#+K><$GUMPI<* zB!I>rK7bEp{ASw}Fv2FgbNepmJKvf8{paT|08@COA;i!xoT__Zn6@PxY3y1?Zkx-u zmQ!-~5*ZBM4%mhpOHN0?GW6T?8T%lD)qs>(BKO3QT$mM?`PJccH@ZTX2w zN>I2s!yLo)Dz_75;ro0`Cn)uW>H4HFx z|CbOQLl|bzwuDq1F?1zUwTMC2R-{M#%|&q&2@SW-b+mS-V-&Y3faT}Q6?qU8zTSc) z(i&0>eHV97#~8*LS_6w*AR@9qPeEQOtae5qCNQbNVCX#;^o)&;4DK;ReIau$DZ-(G zy6X&`tw-@PfhipiRI6Hj;gpIs9YryNSq%>vI#0Em-#0}?X;jA}4N5V%h?fMP8{ZExO|FdZt*ilon&B7j{Cypq;#9+OAJMFABNslECzr z4qeKe&3#|^7$&WU>AiwbJg&qK#59-J~w-q{_w$W^s)?pfB>9J$9r^k;GPk%?p zVPM!z-zG8y)^Lr!%85+TgI*fxW}~kj=1Vxr32vNVc zi{mGlJ`8}2Ab~lGrN+kuL}l!woWOg6w~j%4ptFx8-cLxu3{VUQfYWspKpIc+jBt!1 nf-Dv&ZjSuv*H_Xo6CvY8T85Cv5{(g(d?%jMEJ`k_9D4o&H|a}{ literal 0 HcmV?d00001 diff --git a/target/classes/envoy/client/ui/ChatWindow.class b/target/classes/envoy/client/ui/ChatWindow.class new file mode 100644 index 0000000000000000000000000000000000000000..c87f19692479e0c967a3e01a0aa9ac74b280dc22 GIT binary patch literal 2409 zcmaJ@%~umw6#qRkNn{)Z1k{L9wUmYkMvGMoR)io54WOW4lxio*5C$hRbY?=JEwx|v zOZ)wCPJ2#w-E`?WCTW|V{sHaMrCoICIc+!Hbl3L2nFJECorKBEefQqqy}x_kef;$I z_dfzSjL-e3Vc4nYOU6n#p{a^)hcjw8GB4XRs-85meh3U(7vv>*Ic#NBJry1uHs!R! zusLDqHtC<0b$V-#R_Sn|)<;T?=ZNE&aH3T}r#Py+MykH!s;=567(BtwX$B!;Boz@J z)Jdp?=tn)nj{hG{TkG%|AI0s=lYlkC- zW|$)O;87lZJ7ve+akN%+NO&AUhB}TWC$6PT4$06IbU0kM?{oD-684w%hYeG4_5J8( zXsaYWZkS2M44+Cb+AD+3vxqK)c>p^(?jZ?Jpr@QA*ChuoX1TT{7p}Df&+w##BRERQ zQMi%Hl5ekySGQ$VS4=YU<0*!1YgC*z)#RX@ipncS#ujmmvvv%}B|Hr(wv;fmOj@5& zllDBZUUPYbubz}Jz*j}n$evNu)Vyu^`tSBQm#_c3FZlH(S3E7@3`U5{k{ef-`x)}} zf8*-;`fvYsqwU*szjK2L31_(h_dMfjb8aRjOyRuCjTet+l=oA6DR1xO7X$d+EYDv|R zGc>OEovYf%DS2Lk2`Y(4PEvDrR*(@f(u;;pTffgW)MOe96Y&KlVLRo|P%l?eGnlb$ zL*Ilf<#E=qs0(bY@V>k{6;4Pt}x9Z2vA5mhZ3aD1EWtH@qi;zP1pgIo~dyvXC3 zbX+md%W;i{;?}5JDA@BV(YovZ0wrguxOTN_!tPkFQq`8C(bnx z6b)pP_u-tXXjHWAj>*P^89Gw&#MQL1q)aIqm5q`ed$^0;8&E5{l%T~$s;66DilZ9O z6_Zly1~lFUWh-&Y$e0ObSml(}uOB@Jcn{Hp7}2Q)5lyx%#ll`1*B&~$YUo2_m!7~U zKHX_^P!I5NzL}OalF}->6)Hdq6|p5&Ktm3VAzvO%p@w8bva#l3qi0VZ+iA6xR(I#n z7P^DBBKE`@@r(N{U|$}OmBk*9#}Rb8g09#mx(Yau$H5R6<#D)(W8|why5IMM81o1d zF@gTP!bA>z8%6yj^2a>Q7@Uj=^^-AgGlnK}7%q!P*Thj0k8_Cqd7LZa0%6RIbqRS~ zEMk^ku8emJIb7wpM7KAGx$Yv=ScB+(3b>Yo#?8CB^H?mxj%{5kV7XTa2yVLnG=hJf z>|S(*o`$5G?Mo$yUT?t5K>}U^NI3VofcN1z0U_WeB<^W77V0YCdLFOcrYhCoO}f8} zeRS`DfOgc=Y1oV)NjlMu5QgZqyFdq5irx$yKo()rKZvhz2zTfN`x!mBi=((l)BIQT z;y(KD2ae-UI#B+?022{mO*qZkaEA5JsE^Q+58xrcIzGfl^nXzlC-E`KytMua+121v Od`7>#2UqEru73dwM|N5O literal 0 HcmV?d00001 From 8b9443c45606d60b79bb5bca94f2e391ead4f27c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 30 Sep 2019 09:53:16 +0200 Subject: [PATCH 006/474] Moved main method to ChatWindow, made message sending asynchronous --- src/main/java/envoy/EnvoyClient.java | 47 ------- src/main/java/envoy/client/EnvoyClient.java | 103 ++++++-------- src/main/java/envoy/client/ui/ChatWindow.java | 133 ++++++++---------- 3 files changed, 104 insertions(+), 179 deletions(-) delete mode 100644 src/main/java/envoy/EnvoyClient.java diff --git a/src/main/java/envoy/EnvoyClient.java b/src/main/java/envoy/EnvoyClient.java deleted file mode 100644 index 1ba3dc1..0000000 --- a/src/main/java/envoy/EnvoyClient.java +++ /dev/null @@ -1,47 +0,0 @@ -package envoy; - -import java.time.Instant; - -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Response; -import javax.xml.bind.JAXBException; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeFactory; - -import envoy.schema.Message; -import envoy.schema.ObjectFactory; - -/** - * Project: envoy-client
- * File: EnvoyClient.java
- * Created: 28 Sep 2019
- * Author: Kai S. K. Engelbart - */ -public class EnvoyClient { - - public static void main(String[] args) throws DatatypeConfigurationException, JAXBException { - ObjectFactory factory = new ObjectFactory(); - - Message.MetaData metaData = factory.createMessageMetaData(); - metaData.setSender("Kai"); - metaData.setRecipient("Maxi"); - metaData.setState(false); - metaData.setDate(DatatypeFactory.newInstance().newXMLGregorianCalendar(Instant.now().toString())); - - Message.Content content = factory.createMessageContent(); - content.setType("text"); - content.setText("Hello, World"); - - Message message = factory.createMessage(); - message.setMetaData(metaData); - message.getContent().add(content); - - Client client = ClientBuilder.newClient(); - WebTarget target = client.target("http://localhost:8080/envoy-server/rest/message/send"); - Response response = target.request().post(Entity.entity(message, "application/xml")); - response.close(); - } -} diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index ecb58b2..a7f4e6d 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -1,8 +1,5 @@ package envoy.client; -import java.awt.EventQueue; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.time.Instant; import javax.ws.rs.client.Client; @@ -10,11 +7,9 @@ import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; -import javax.xml.bind.JAXBException; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; -import envoy.client.ui.ChatWindow; import envoy.schema.Message; import envoy.schema.ObjectFactory; @@ -22,68 +17,54 @@ import envoy.schema.ObjectFactory; * Project: envoy-client
* File: EnvoyClient.java
* Created: 28 Sep 2019
- * Author: Kai S. K. Engelbart and Maximilian Käfer + * Author: Kai S. K. Engelbart & Maximilian Käfer */ public class EnvoyClient { - public static String content1 = ""; - - - /** - * Calls Class ChatWidow - */ - public static void main(String[] args) throws DatatypeConfigurationException, JAXBException { - EventQueue.invokeLater(new Runnable() { - public void run() { - try { - ChatWindow frame = new ChatWindow(); - frame.setVisible(true); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - - /** - * specifies data
- * sends xml to server
- * gets response from server (currently 204) - */ - public static void sendMessage() throws DatatypeConfigurationException, JAXBException { - - ObjectFactory factory = new ObjectFactory(); - - Message.MetaData metaData = factory.createMessageMetaData(); - metaData.setSender("Kai"); - metaData.setRecipient("Maxi"); - metaData.setState(false); - metaData.setDate(DatatypeFactory.newInstance().newXMLGregorianCalendar(Instant.now().toString())); + private DatatypeFactory datatypeFactory; - Message.Content content = factory.createMessageContent(); - content.setType("text"); - content.setText(content1); - - Message message = factory.createMessage(); - message.setMetaData(metaData); - message.getContent().add(content); - - Client client = ClientBuilder.newClient(); - WebTarget target = client.target("http://localhost:8080/envoy-server/rest/message/send"); - Response response = target.request().post(Entity.entity(message, "application/xml")); - System.out.println("Response code: " + response.getStatus()); - response.close(); - - - + public EnvoyClient() { + try { + datatypeFactory = DatatypeFactory.newInstance(); + } catch (DatatypeConfigurationException e) { + e.printStackTrace(); + } } - + /** - * sets content of xml to content from ChatWindow + * Sends a message with text content to the server.
+ * Because sending a request is a blocking operation, it is executed + * asynchronously. + * + * @param sender Name of the sender + * @param recipient Name of the recipient + * @param textContent Content (text) of the message */ - public void setContent (String content2) { - content1 = content2; + public void sendMessage(String sender, String recipient, String textContent) { + new Thread(() -> { + ObjectFactory factory = new ObjectFactory(); + + Message.MetaData metaData = factory.createMessageMetaData(); + metaData.setSender(sender); + metaData.setRecipient(recipient); + metaData.setState(false); + metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); + + Message.Content content = factory.createMessageContent(); + content.setType("text"); + content.setText(textContent); + + Message message = factory.createMessage(); + message.setMetaData(metaData); + message.getContent().add(content); + + Client client = ClientBuilder.newClient(); + WebTarget target = client.target("http://localhost:8080/envoy-server/rest/message/send"); + Response response = target.request().post(Entity.entity(message, "application/xml")); + System.out.println("Response code: " + response.getStatus()); + response.close(); + client.close(); + }).start(); } - -} +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index dad7788..10fa35a 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,108 +1,99 @@ package envoy.client.ui; -import java.awt.BorderLayout; +import java.awt.Color; import java.awt.EventQueue; - -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.JTextPane; -import javax.swing.border.EmptyBorder; -import javax.xml.bind.JAXBException; -import javax.xml.datatype.DatatypeConfigurationException; - -import envoy.client.EnvoyClient; - +import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import javax.swing.JButton; -import java.awt.GridBagConstraints; -import java.awt.Color; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.border.EmptyBorder; + +import envoy.client.EnvoyClient; /** * Project: envoy-client
* File: ChatWindow.java
* Created: 28 Sep 2019
- * Author: Maximilian Käfer + * Author: Maximilian Käfer & Kai S. K. Engelbart */ - public class ChatWindow extends JFrame { - private JPanel contentPane; - EnvoyClient envoyClient = new EnvoyClient(); + private static final long serialVersionUID = 6865098428255463649L; + + private JPanel contentPane = new JPanel(); + private EnvoyClient envoyClient = new EnvoyClient(); public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); - contentPane = new JPanel(); + setTitle("Envoy"); + setLocationRelativeTo(null); + contentPane.setBackground(new Color(220, 220, 220)); - contentPane.setForeground(new Color(0, 0, 0)); + contentPane.setForeground(Color.white); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); GridBagLayout gbl_contentPane = new GridBagLayout(); - gbl_contentPane.columnWidths = new int[]{1, 1, 1}; - gbl_contentPane.rowHeights = new int[]{1, 1, 1}; - gbl_contentPane.columnWeights = new double[]{0.3, 1.0, 0.1}; - gbl_contentPane.rowWeights = new double[]{0.05, 1, 0.07}; + gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; + gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; + gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; + gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; contentPane.setLayout(gbl_contentPane); - - - // Message enter field ---------------------------------------------------------------------------- - JTextArea messageEnterTextfield = new JTextArea(); - messageEnterTextfield.setLineWrap(true); - - GridBagConstraints gbc_moveSelectionMessageEnterTextfield = new GridBagConstraints(); - gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; - gbc_moveSelectionMessageEnterTextfield.gridx = 1; - gbc_moveSelectionMessageEnterTextfield.gridy = 2; - - //gbc_moveSelectionMessageEnterTextfield.gridwidth = 10; - - gbc_moveSelectionMessageEnterTextfield.insets = new Insets(10, 10, 10, 10); - - contentPane.add(messageEnterTextfield, gbc_moveSelectionMessageEnterTextfield); - - // Post Button ----------------------------------------------------------------------------------- + // Message enter field + JTextArea messageEnterTextfield = new JTextArea(); + messageEnterTextfield.setLineWrap(true); + + GridBagConstraints gbc_moveSelectionMessageEnterTextfield = new GridBagConstraints(); + gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; + gbc_moveSelectionMessageEnterTextfield.gridx = 1; + gbc_moveSelectionMessageEnterTextfield.gridy = 2; + + gbc_moveSelectionMessageEnterTextfield.insets = new Insets(10, 10, 10, 10); + + contentPane.add(messageEnterTextfield, gbc_moveSelectionMessageEnterTextfield); + + // Post Button JButton postButton = new JButton("Post"); postButton.setForeground(new Color(255, 255, 255)); postButton.setBackground(new Color(0, 100, 0)); GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); - + gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; gbc_moveSelectionPostButton.gridx = 2; gbc_moveSelectionPostButton.gridy = 2; - + gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); - + contentPane.add(postButton, gbc_moveSelectionPostButton); - - - postButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - try { - if(messageEnterTextfield.getText().isEmpty() == false) { - envoyClient.setContent(messageEnterTextfield.getText()); - envoyClient.sendMessage(); - } - - } catch (DatatypeConfigurationException | JAXBException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - } - }); - - - - - + + postButton.addActionListener((evt) -> { + if (!messageEnterTextfield.getText().isEmpty()) try { + envoyClient.sendMessage("Kai", "Maxi", messageEnterTextfield.getText()); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "An exception occured while sending a message. See the log for more details.", + "Exception occured", + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + }); } -} + public static void main(String[] args) { + EventQueue.invokeLater(() -> { + try { + ChatWindow frame = new ChatWindow(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } +} \ No newline at end of file From 84cd545f749abd96c23fac17a4d7e248de1d9e2b Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 30 Sep 2019 10:01:41 +0200 Subject: [PATCH 007/474] Delete ChatWindow$1.class --- .../classes/envoy/client/ui/ChatWindow$1.class | Bin 1329 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 target/classes/envoy/client/ui/ChatWindow$1.class diff --git a/target/classes/envoy/client/ui/ChatWindow$1.class b/target/classes/envoy/client/ui/ChatWindow$1.class deleted file mode 100644 index 9c7d5d4553243fde0abf0b0939b2592023cd0cce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1329 zcmaJ>>rN9v7(LTg7Ro{^7eVBzMcaZbRRj^dlu}gEstE)Y6XUQQU~#+K><$GUMPI<* zB!I>rK7bEp{ASw}Fv2FgbNepmJKvf8{paT|08@COA;i!xoT__Zn6@PxY3y1?Zkx-u zmQ!-~5*ZBM4%mhpOHN0?GW6T?8T%lD)qs>(BKO3QT$mM?`PJccH@ZTX2w zN>I2s!yLo)Dz_75;ro0`Cn)uW>H4HFx z|CbOQLl|bzwuDq1F?1zUwTMC2R-{M#%|&q&2@SW-b+mS-V-&Y3faT}Q6?qU8zTSc) z(i&0>eHV97#~8*LS_6w*AR@9qPeEQOtae5qCNQbNVCX#;^o)&;4DK;ReIau$DZ-(G zy6X&`tw-@PfhipiRI6Hj;gpIs9YryNSq%>vI#0Em-#0}?X;jA}4N5V%h?fMP8{ZExO|FdZt*ilon&B7j{Cypq;#9+OAJMFABNslECzr z4qeKe&3#|^7$&WU>AiwbJg&qK#59-J~w-q{_w$W^s)?pfB>9J$9r^k;GPk%?p zVPM!z-zG8y)^Lr!%85+TgI*fxW}~kj=1Vxr32vNVc zi{mGlJ`8}2Ab~lGrN+kuL}l!woWOg6w~j%4ptFx8-cLxu3{VUQfYWspKpIc+jBt!1 nf-Dv&ZjSuv*H_Xo6CvY8T85Cv5{(g(d?%jMEJ`k_9D4o&H|a}{ From f143794aaa632a738ef7f1fb6d7ee133295d7515 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 30 Sep 2019 10:01:53 +0200 Subject: [PATCH 008/474] Delete ChatWindow.class --- target/classes/envoy/client/ui/ChatWindow.class | Bin 2409 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 target/classes/envoy/client/ui/ChatWindow.class diff --git a/target/classes/envoy/client/ui/ChatWindow.class b/target/classes/envoy/client/ui/ChatWindow.class deleted file mode 100644 index c87f19692479e0c967a3e01a0aa9ac74b280dc22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2409 zcmaJ@%~umw6#qRkNn{)Z1k{L9wUmYkMvGMoR)io54WOW4lxio*5C$hRbY?=JEwx|v zOZ)wCPJ2#w-E`?WCTW|V{sHaMrCoICIc+!Hbl3L2nFJECorKBEefQqqy}x_kef;$I z_dfzSjL-e3Vc4nYOU6n#p{a^)hcjw8GB4XRs-85meh3U(7vv>*Ic#NBJry1uHs!R! zusLDqHtC<0b$V-#R_Sn|)<;T?=ZNE&aH3T}r#Py+MykH!s;=567(BtwX$B!;Boz@J z)Jdp?=tn)nj{hG{TkG%|AI0s=lYlkC- zW|$)O;87lZJ7ve+akN%+NO&AUhB}TWC$6PT4$06IbU0kM?{oD-684w%hYeG4_5J8( zXsaYWZkS2M44+Cb+AD+3vxqK)c>p^(?jZ?Jpr@QA*ChuoX1TT{7p}Df&+w##BRERQ zQMi%Hl5ekySGQ$VS4=YU<0*!1YgC*z)#RX@ipncS#ujmmvvv%}B|Hr(wv;fmOj@5& zllDBZUUPYbubz}Jz*j}n$evNu)Vyu^`tSBQm#_c3FZlH(S3E7@3`U5{k{ef-`x)}} zf8*-;`fvYsqwU*szjK2L31_(h_dMfjb8aRjOyRuCjTet+l=oA6DR1xO7X$d+EYDv|R zGc>OEovYf%DS2Lk2`Y(4PEvDrR*(@f(u;;pTffgW)MOe96Y&KlVLRo|P%l?eGnlb$ zL*Ilf<#E=qs0(bY@V>k{6;4Pt}x9Z2vA5mhZ3aD1EWtH@qi;zP1pgIo~dyvXC3 zbX+md%W;i{;?}5JDA@BV(YovZ0wrguxOTN_!tPkFQq`8C(bnx z6b)pP_u-tXXjHWAj>*P^89Gw&#MQL1q)aIqm5q`ed$^0;8&E5{l%T~$s;66DilZ9O z6_Zly1~lFUWh-&Y$e0ObSml(}uOB@Jcn{Hp7}2Q)5lyx%#ll`1*B&~$YUo2_m!7~U zKHX_^P!I5NzL}OalF}->6)Hdq6|p5&Ktm3VAzvO%p@w8bva#l3qi0VZ+iA6xR(I#n z7P^DBBKE`@@r(N{U|$}OmBk*9#}Rb8g09#mx(Yau$H5R6<#D)(W8|why5IMM81o1d zF@gTP!bA>z8%6yj^2a>Q7@Uj=^^-AgGlnK}7%q!P*Thj0k8_Cqd7LZa0%6RIbqRS~ zEMk^ku8emJIb7wpM7KAGx$Yv=ScB+(3b>Yo#?8CB^H?mxj%{5kV7XTa2yVLnG=hJf z>|S(*o`$5G?Mo$yUT?t5K>}U^NI3VofcN1z0U_WeB<^W77V0YCdLFOcrYhCoO}f8} zeRS`DfOgc=Y1oV)NjlMu5QgZqyFdq5irx$yKo()rKZvhz2zTfN`x!mBi=((l)BIQT z;y(KD2ae-UI#B+?022{mO*qZkaEA5JsE^Q+58xrcIzGfl^nXzlC-E`KytMua+121v Od`7>#2UqEru73dwM|N5O From 201f2504772b17c03f5b350e0cf6bc3428a1f1cc Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 30 Sep 2019 10:02:03 +0200 Subject: [PATCH 009/474] Delete EnvoyClient$1.class --- target/classes/envoy/client/EnvoyClient$1.class | Bin 784 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 target/classes/envoy/client/EnvoyClient$1.class diff --git a/target/classes/envoy/client/EnvoyClient$1.class b/target/classes/envoy/client/EnvoyClient$1.class deleted file mode 100644 index e179dc4c53c39ceda3a0b8111b08a067de72070a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 784 zcmZ`%QE$^Q5dPeyP03QWcC@TxumKySs~|$+ZHSkuNJtqVIu!v=ZfaVO)Tt78uwTUU zUN#9NegHoTadsy*CKky#pZ(o;_ucu|@9#eWJVo0@fniOk!}KVO6DgDqyT<9*{nir~ z4#V;RKjdM;)hK*DI1sURQDUf_pT3gNm#L95T;bkd>luz*D$F3Jo` zkyPT)#E#k`bgH{fC(DDwc1LPtRm~y>ynv;)OJ=T)r@f$0nY-*Hv+n=2DIJ zgdV3u7Y`U#uj-MH04@`_8+=4$hOY4g)%T}ZiQ3KyZhS*I zYM)^B*v3@|-=yS*wP6bgD85C^J2byG>Ud Date: Mon, 30 Sep 2019 10:02:12 +0200 Subject: [PATCH 010/474] Delete EnvoyClient.class --- target/classes/envoy/client/EnvoyClient.class | Bin 3564 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 target/classes/envoy/client/EnvoyClient.class diff --git a/target/classes/envoy/client/EnvoyClient.class b/target/classes/envoy/client/EnvoyClient.class deleted file mode 100644 index 9d662b44ff247cb6283d8472959c98477c5d5d75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3564 zcmai1i(eeo75**(28M~ojZsm=B#r43Ad`?ZC2XQ5NDO3&F(7%^YKP?pCfS`?XJ&cy zrMA9XZLMw9zO-q5_GxT4U|MbKv-aITsK0)9W)^l~Q26ninS0MU_nhy1=iI|b|9kT- z0K4&D4Rr$7NN3ueGjn-cI)OQ$KKjFV4fO)+&RWx!nYWxt^Y-zxG8YIm`sAH zc4>Pg@N8!?!~K1<<=DYZ0&CJ8V*>U4?u2YYivXG-u+~5W8U-%T+KxP0DvV2S)EduA zWzNl6`7z70)pxwuxGyxOV+~RU)}e_8gDKk=xHh|*>-3_&VA+nqRq4A{`ly`J2WE4! z7}&1kYiJeNsUn#*XA60A!V0Wlt|-l0S?%6plwNQ+;%3+p#vum zR!Lk>FIRJN%T66_Na@&!%^EfdtPjDoW|)O(;(JF)mZX7CVT(YE&AgnGSu2p9z}4xh zn2whmN5Pc|p|-q9BC|drXd3aQGchcE-2?b5pWl#rZvC?ssst+4DirX1O;6~vKTv-tgt1|{g#dL>(;}{`L=}{T$bXihPzm+GP7UA5V1ZPqtN$T{c2X`76!wCV6n34#@qARkwtb`H`DCpBTW#BaK zVjMNhVy&s>BCv5aV#N~V)#p_!kh4tkJ+L%EYft@$AwjX3#P{NFcX@Sc^hAr+Gn8h6FWlc;htD>l#XF5*n_!7RN;md?P;_{4d zdVb|Xi0*=eB|FbTH1Jj2$I2wJqIH&X?98m0pvD|MAh3HX2#S5CnOEI?%JqZ3-W|O= z%n++?UwYHhGd<}CW+CcLrs`8I_&Ofa@Ss5Js$Lm*7>@`v2JCv0l0;FtInIZXzs%b~<-*^cd7Ik0;@ixh`=&S z)d`{{oh^H@{Z;1A9Ahs)G=xZaM-!xg2^ zIX2cY`BYjB+b-gYz;m(X_VBHHJ1 z!;(3jo4}3GVOE)J;mX#~~Iyu~x`dk@zcU^!{Mvg0Ij&^sJakjgRV%GwKI-Hot7yIg4 z>r?kH;A?g0YiMm)z@q})sVC?0?FD?FYmFE1qf0n{D)sY=c&W9qj91F|br~1Rctd^7 zF9kS+6dmnl7=2jFL2y0xp%wel&e?A}Zow`NMtgCPZ=B=!JA^~H6Nfp13~~e*!W@p^ zX=L#%j)edn4%7M+F5wTfyO#a`k9dpt?!pt<8 From 8ad8ee13bc9f479e1a122cb40ec34b5c1cf436f3 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 30 Sep 2019 10:02:24 +0200 Subject: [PATCH 011/474] Delete pom.properties --- .../maven/informatik-ag-ngl/envoy-client/pom.properties | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.properties diff --git a/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.properties b/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.properties deleted file mode 100644 index d1fda1a..0000000 --- a/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.properties +++ /dev/null @@ -1,7 +0,0 @@ -#Generated by Maven Integration for Eclipse -#Sun Sep 29 16:49:31 CEST 2019 -m2e.projectLocation=C\:\\Users\\Maxi\\git\\envoy-client -m2e.projectName=envoy-client -groupId=informatik-ag-ngl -artifactId=envoy-client -version=0.0.1-SNAPSHOT From 4e10010e098859e6520e869f6e3bd830876f0b24 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 30 Sep 2019 10:02:31 +0200 Subject: [PATCH 012/474] Delete pom.xml --- .../informatik-ag-ngl/envoy-client/pom.xml | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.xml diff --git a/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.xml b/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.xml deleted file mode 100644 index d688c37..0000000 --- a/target/classes/META-INF/maven/informatik-ag-ngl/envoy-client/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - 4.0.0 - - informatik-ag-ngl - envoy-client - 0.0.1-SNAPSHOT - - Envoy Client - https://github.com/informatik-ag-ngl/envoy-client - - - UTF-8 - UTF-8 - 1.8 - 1.8 - - - - - org.jboss.resteasy - resteasy-client - 4.1.1.Final - - - org.jboss.resteasy - resteasy-jaxb-provider - 4.3.1.Final - - - informatik-ag-ngl - envoy-common - 0.0.1-SNAPSHOT - - - - - envoy-client - - \ No newline at end of file From fd463abd2b98ad7e89c779590656f7f4de126e86 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 30 Sep 2019 10:02:40 +0200 Subject: [PATCH 013/474] Delete MANIFEST.MF --- target/classes/META-INF/MANIFEST.MF | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 target/classes/META-INF/MANIFEST.MF diff --git a/target/classes/META-INF/MANIFEST.MF b/target/classes/META-INF/MANIFEST.MF deleted file mode 100644 index aaa130c..0000000 --- a/target/classes/META-INF/MANIFEST.MF +++ /dev/null @@ -1,5 +0,0 @@ -Manifest-Version: 1.0 -Built-By: Maxi -Build-Jdk: 12.0.1 -Created-By: Maven Integration for Eclipse - From 7f32cd9072c9e67741781d955c51a011164200cd Mon Sep 17 00:00:00 2001 From: Maxi Date: Sat, 5 Oct 2019 10:07:52 +0200 Subject: [PATCH 014/474] Added Message List --- src/main/java/envoy/client/EnvoyClient.java | 41 +++--- src/main/java/envoy/client/ui/ChatWindow.java | 124 +++++++++++++++++- 2 files changed, 141 insertions(+), 24 deletions(-) diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index a7f4e6d..9316504 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -10,6 +10,7 @@ import javax.ws.rs.core.Response; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; +import envoy.client.ui.ChatWindow; import envoy.schema.Message; import envoy.schema.ObjectFactory; @@ -41,24 +42,9 @@ public class EnvoyClient { * @param recipient Name of the recipient * @param textContent Content (text) of the message */ - public void sendMessage(String sender, String recipient, String textContent) { + public void sendMessage(Message message) { + //System.out.println(message.getContent().get(0).getText()); new Thread(() -> { - ObjectFactory factory = new ObjectFactory(); - - Message.MetaData metaData = factory.createMessageMetaData(); - metaData.setSender(sender); - metaData.setRecipient(recipient); - metaData.setState(false); - metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); - - Message.Content content = factory.createMessageContent(); - content.setType("text"); - content.setText(textContent); - - Message message = factory.createMessage(); - message.setMetaData(metaData); - message.getContent().add(content); - Client client = ClientBuilder.newClient(); WebTarget target = client.target("http://localhost:8080/envoy-server/rest/message/send"); Response response = target.request().post(Entity.entity(message, "application/xml")); @@ -67,4 +53,25 @@ public class EnvoyClient { client.close(); }).start(); } + + + public Message createMessage(String senderID, String recipientID, String textContent) { + ObjectFactory factory = new ObjectFactory(); + Message.MetaData metaData = factory.createMessageMetaData(); + metaData.setSender(senderID); + metaData.setRecipient(recipientID); + metaData.setState(false); + metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); + + Message.Content content = factory.createMessageContent(); + content.setType("text"); + content.setText(textContent); + + Message message = factory.createMessage(); + message.setMetaData(metaData); + message.getContent().add(content); + + + return message; + } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 10fa35a..dde872c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,25 +1,47 @@ package envoy.client.ui; import java.awt.Color; +import java.awt.Component; import java.awt.EventQueue; +import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.util.Iterator; +import java.util.List; +import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JFrame; +import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JScrollPane; import javax.swing.JTextArea; +import javax.swing.ListModel; +import javax.swing.border.Border; import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; +import javax.swing.border.MatteBorder; import envoy.client.EnvoyClient; +import envoy.schema.Message; + +import javax.swing.ListSelectionModel; +import javax.swing.UIManager; + +import java.awt.Rectangle; +import java.awt.geom.RoundRectangle2D; +import java.awt.ComponentOrientation; +import java.awt.Point; +import java.awt.Dimension; +import javax.swing.border.BevelBorder; /** * Project: envoy-client
* File: ChatWindow.java
* Created: 28 Sep 2019
- * Author: Maximilian Käfer & Kai S. K. Engelbart + * Author: Maximilian Käfer & Kai S. K. Engelbart & Leon Hofmeister */ public class ChatWindow extends JFrame { @@ -28,13 +50,14 @@ public class ChatWindow extends JFrame { private JPanel contentPane = new JPanel(); private EnvoyClient envoyClient = new EnvoyClient(); + public DefaultListModel listModel = new DefaultListModel<>(); public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); setTitle("Envoy"); setLocationRelativeTo(null); - contentPane.setBackground(new Color(220, 220, 220)); + contentPane.setBackground(new Color(0, 0, 0)); contentPane.setForeground(Color.white); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); @@ -45,9 +68,61 @@ public class ChatWindow extends JFrame { gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; contentPane.setLayout(gbl_contentPane); - // Message enter field + + // Chat------------------ + List testMessages = List.of(envoyClient.createMessage("UserA", "UserB", "Das ist eine Testnachricht."), envoyClient.createMessage("UserB", "UserA", "Das ist die Antwort auf die Testnachricht.")); + + JList elementList = new JList<>(); + elementList.setFocusTraversalKeysEnabled(false); + + elementList.setSelectionForeground(new Color(255, 255, 255)); + elementList.setSelectionBackground(new Color(102, 0, 153)); + elementList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + elementList.setForeground(new Color(255, 255, 255)); + elementList.setBackground(new Color(51, 51, 51)); + + + + elementList.setModel(listModel); + elementList.setFont( new Font("Arial", Font.PLAIN, 17)); + elementList.setFixedCellHeight(60); + elementList.setBorder(new EmptyBorder(5, 5, 5, 5)); + + + //Only temporary for the predefined messages in the List + for (int i = 0; i < testMessages.size(); i++) { + listModel.addElement("" + "

" + getSenderElement(testMessages.get(i)) + " " + "
" + "

" + getFirstContentElement(testMessages.get(i)) + ""); + } + + + + JScrollPane scrollPane = new JScrollPane(); + scrollPane.setForeground(new Color(0, 0, 0)); + scrollPane.setBackground(new Color(51, 51, 51)); + scrollPane.setViewportView(elementList); + scrollPane.setBorder(null); + + GridBagConstraints gbc_scrollPane = new GridBagConstraints(); + gbc_scrollPane.fill = GridBagConstraints.BOTH; + gbc_scrollPane.gridwidth = 2; + gbc_scrollPane.gridx = 1; + gbc_scrollPane.gridy = 1; + + + gbc_scrollPane.insets = new Insets(10, 10, 10, 10); + + contentPane.add(scrollPane, gbc_scrollPane); + + + // Message enter field----------------- JTextArea messageEnterTextfield = new JTextArea(); + messageEnterTextfield.setCaretColor(new Color(255, 255, 255)); + messageEnterTextfield.setForeground(new Color(255, 255, 255)); + messageEnterTextfield.setBackground(new Color(51, 51, 51)); messageEnterTextfield.setLineWrap(true); + messageEnterTextfield.setBorder(null); + messageEnterTextfield.setFont( new Font("Arial", Font.PLAIN, 17)); + messageEnterTextfield.setBorder(new EmptyBorder(5, 5, 5, 5)); GridBagConstraints gbc_moveSelectionMessageEnterTextfield = new GridBagConstraints(); gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; @@ -58,10 +133,14 @@ public class ChatWindow extends JFrame { contentPane.add(messageEnterTextfield, gbc_moveSelectionMessageEnterTextfield); - // Post Button + + + + // Post Button----------------- JButton postButton = new JButton("Post"); postButton.setForeground(new Color(255, 255, 255)); - postButton.setBackground(new Color(0, 100, 0)); + postButton.setBackground(new Color(102, 51, 153)); + postButton.setBorderPainted(false); GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); @@ -71,11 +150,14 @@ public class ChatWindow extends JFrame { gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); + contentPane.add(postButton, gbc_moveSelectionPostButton); postButton.addActionListener((evt) -> { if (!messageEnterTextfield.getText().isEmpty()) try { - envoyClient.sendMessage("Kai", "Maxi", messageEnterTextfield.getText()); + envoyClient.sendMessage(envoyClient.createMessage("Kai", "Maxi", messageEnterTextfield.getText())); + addMessageToChat("Du", messageEnterTextfield.getText()); + messageEnterTextfield.setText(""); } catch (Exception e) { JOptionPane.showMessageDialog(this, "An exception occured while sending a message. See the log for more details.", @@ -85,7 +167,35 @@ public class ChatWindow extends JFrame { } }); } - + + /** + * gets the Sender from the Message + * @param message + * @return + */ + public String getSenderElement (Message message) { + return message.getMetaData().getSender(); + } + + /** + * gets the First Content Element(text) from the Message + * @param message + * @return + */ + public String getFirstContentElement (Message message) { + return message.getContent().get(0).getText(); + } + + /** + * adds the Sender and the First Content Element(text) of the new Message to the listModel + * @param message + * @return + */ + public void addMessageToChat(String Sender, String Content) { + listModel.addElement("" + "

" + Sender + " " + "
" + "

" + Content + ""); + } + + public static void main(String[] args) { EventQueue.invokeLater(() -> { try { From b96f28921eaf664db338a7a66e3c776a5ee7e27d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 5 Oct 2019 12:48:21 +0200 Subject: [PATCH 015/474] Improved code style, added debug XML output --- src/main/java/envoy/client/EnvoyClient.java | 41 ++++-- src/main/java/envoy/client/ui/ChatWindow.java | 135 ++++++------------ 2 files changed, 77 insertions(+), 99 deletions(-) diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index 9316504..a6f5fb9 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -7,10 +7,12 @@ import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; -import envoy.client.ui.ChatWindow; import envoy.schema.Message; import envoy.schema.ObjectFactory; @@ -43,21 +45,39 @@ public class EnvoyClient { * @param textContent Content (text) of the message */ public void sendMessage(Message message) { - //System.out.println(message.getContent().get(0).getText()); new Thread(() -> { - Client client = ClientBuilder.newClient(); - WebTarget target = client.target("http://localhost:8080/envoy-server/rest/message/send"); - Response response = target.request().post(Entity.entity(message, "application/xml")); + // Print message XML to console + JAXBContext jc; + try { + jc = JAXBContext.newInstance("envoy.schema"); + Marshaller m = jc.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.marshal(message, System.out); + } catch (JAXBException e) { + e.printStackTrace(); + } + + // Send message + Client client = ClientBuilder.newClient(); + WebTarget target = client.target("http://kske.feste-ip.net:43315/envoy-server/rest/message/send"); + Response response = target.request().post(Entity.entity(message, "application/xml")); System.out.println("Response code: " + response.getStatus()); response.close(); client.close(); }).start(); } - - + + /** + * Creates a {@link Message} object serializable to XML. + * + * @param senderID The ID of the sender + * @param recipientID The ID of the recipient + * @param textContent The content (text) of the message + * @return Prepared {@link Message} object + */ public Message createMessage(String senderID, String recipientID, String textContent) { - ObjectFactory factory = new ObjectFactory(); - Message.MetaData metaData = factory.createMessageMetaData(); + ObjectFactory factory = new ObjectFactory(); + Message.MetaData metaData = factory.createMessageMetaData(); metaData.setSender(senderID); metaData.setRecipient(recipientID); metaData.setState(false); @@ -70,8 +90,7 @@ public class EnvoyClient { Message message = factory.createMessage(); message.setMetaData(metaData); message.getContent().add(content); - - + return message; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index dde872c..8fb801e 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,14 +1,12 @@ package envoy.client.ui; import java.awt.Color; -import java.awt.Component; +import java.awt.ComponentOrientation; import java.awt.EventQueue; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; -import java.util.Iterator; -import java.util.List; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -18,39 +16,26 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; -import javax.swing.ListModel; -import javax.swing.border.Border; import javax.swing.border.EmptyBorder; -import javax.swing.border.LineBorder; -import javax.swing.border.MatteBorder; import envoy.client.EnvoyClient; import envoy.schema.Message; -import javax.swing.ListSelectionModel; -import javax.swing.UIManager; - -import java.awt.Rectangle; -import java.awt.geom.RoundRectangle2D; -import java.awt.ComponentOrientation; -import java.awt.Point; -import java.awt.Dimension; -import javax.swing.border.BevelBorder; - /** * Project: envoy-client
* File: ChatWindow.java
* Created: 28 Sep 2019
- * Author: Maximilian Käfer & Kai S. K. Engelbart & Leon Hofmeister + * Author: Maximilian Käfer & Kai S. K. Engelbart */ public class ChatWindow extends JFrame { private static final long serialVersionUID = 6865098428255463649L; - private JPanel contentPane = new JPanel(); - private EnvoyClient envoyClient = new EnvoyClient(); + private JPanel contentPane = new JPanel(); + private EnvoyClient envoyClient = new EnvoyClient(); public DefaultListModel listModel = new DefaultListModel<>(); + public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); @@ -62,81 +47,62 @@ public class ChatWindow extends JFrame { contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); GridBagLayout gbl_contentPane = new GridBagLayout(); - gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; - gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; - gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; - gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; + gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; + gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; + gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; + gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; contentPane.setLayout(gbl_contentPane); - - // Chat------------------ - List testMessages = List.of(envoyClient.createMessage("UserA", "UserB", "Das ist eine Testnachricht."), envoyClient.createMessage("UserB", "UserA", "Das ist die Antwort auf die Testnachricht.")); - JList elementList = new JList<>(); elementList.setFocusTraversalKeysEnabled(false); - + elementList.setSelectionForeground(new Color(255, 255, 255)); elementList.setSelectionBackground(new Color(102, 0, 153)); elementList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); elementList.setForeground(new Color(255, 255, 255)); elementList.setBackground(new Color(51, 51, 51)); - - - + elementList.setModel(listModel); - elementList.setFont( new Font("Arial", Font.PLAIN, 17)); + elementList.setFont(new Font("Arial", Font.PLAIN, 17)); elementList.setFixedCellHeight(60); elementList.setBorder(new EmptyBorder(5, 5, 5, 5)); - - - //Only temporary for the predefined messages in the List - for (int i = 0; i < testMessages.size(); i++) { - listModel.addElement("" + "

" + getSenderElement(testMessages.get(i)) + " " + "
" + "

" + getFirstContentElement(testMessages.get(i)) + ""); - } - - - + JScrollPane scrollPane = new JScrollPane(); scrollPane.setForeground(new Color(0, 0, 0)); scrollPane.setBackground(new Color(51, 51, 51)); scrollPane.setViewportView(elementList); scrollPane.setBorder(null); - + GridBagConstraints gbc_scrollPane = new GridBagConstraints(); - gbc_scrollPane.fill = GridBagConstraints.BOTH; - gbc_scrollPane.gridwidth = 2; - gbc_scrollPane.gridx = 1; - gbc_scrollPane.gridy = 1; - + gbc_scrollPane.fill = GridBagConstraints.BOTH; + gbc_scrollPane.gridwidth = 2; + gbc_scrollPane.gridx = 1; + gbc_scrollPane.gridy = 1; gbc_scrollPane.insets = new Insets(10, 10, 10, 10); - + contentPane.add(scrollPane, gbc_scrollPane); - - - // Message enter field----------------- + + // Message enter field JTextArea messageEnterTextfield = new JTextArea(); messageEnterTextfield.setCaretColor(new Color(255, 255, 255)); messageEnterTextfield.setForeground(new Color(255, 255, 255)); messageEnterTextfield.setBackground(new Color(51, 51, 51)); messageEnterTextfield.setLineWrap(true); messageEnterTextfield.setBorder(null); - messageEnterTextfield.setFont( new Font("Arial", Font.PLAIN, 17)); + messageEnterTextfield.setFont(new Font("Arial", Font.PLAIN, 17)); messageEnterTextfield.setBorder(new EmptyBorder(5, 5, 5, 5)); GridBagConstraints gbc_moveSelectionMessageEnterTextfield = new GridBagConstraints(); - gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; - gbc_moveSelectionMessageEnterTextfield.gridx = 1; - gbc_moveSelectionMessageEnterTextfield.gridy = 2; + gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; + gbc_moveSelectionMessageEnterTextfield.gridx = 1; + gbc_moveSelectionMessageEnterTextfield.gridy = 2; gbc_moveSelectionMessageEnterTextfield.insets = new Insets(10, 10, 10, 10); contentPane.add(messageEnterTextfield, gbc_moveSelectionMessageEnterTextfield); - - - - // Post Button----------------- + // Post Button JButton postButton = new JButton("Post"); postButton.setForeground(new Color(255, 255, 255)); postButton.setBackground(new Color(102, 51, 153)); @@ -144,19 +110,19 @@ public class ChatWindow extends JFrame { GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); - gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; - gbc_moveSelectionPostButton.gridx = 2; - gbc_moveSelectionPostButton.gridy = 2; + gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; + gbc_moveSelectionPostButton.gridx = 2; + gbc_moveSelectionPostButton.gridy = 2; gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); - contentPane.add(postButton, gbc_moveSelectionPostButton); postButton.addActionListener((evt) -> { if (!messageEnterTextfield.getText().isEmpty()) try { - envoyClient.sendMessage(envoyClient.createMessage("Kai", "Maxi", messageEnterTextfield.getText())); - addMessageToChat("Du", messageEnterTextfield.getText()); + final Message message = envoyClient.createMessage("Kai", "Maxi", messageEnterTextfield.getText()); + envoyClient.sendMessage(message); + appendMessageToChat(message); messageEnterTextfield.setText(""); } catch (Exception e) { JOptionPane.showMessageDialog(this, @@ -167,35 +133,28 @@ public class ChatWindow extends JFrame { } }); } - + /** - * gets the Sender from the Message - * @param message - * @return + * Extracts the first text content from a message. + * + * @param message The message from which to return the text content + * @return The first content of type 'text' */ - public String getSenderElement (Message message) { - return message.getMetaData().getSender(); - } - - /** - * gets the First Content Element(text) from the Message - * @param message - * @return - */ - public String getFirstContentElement (Message message) { + public String getFirstTextContent(Message message) { return message.getContent().get(0).getText(); } - + /** - * adds the Sender and the First Content Element(text) of the new Message to the listModel - * @param message - * @return + * Appends a message with sender and message content to the message list. + * + * @param message The message to append */ - public void addMessageToChat(String Sender, String Content) { - listModel.addElement("" + "

" + Sender + " " + "
" + "

" + Content + ""); + private void appendMessageToChat(Message message) { + listModel.addElement("" + "

" + message.getMetaData().getSender() + + " " + "
" + "

" + getFirstTextContent(message) + + ""); } - - + public static void main(String[] args) { EventQueue.invokeLater(() -> { try { From 87738d011781b48013ff5358d3bf41cf39448c2f Mon Sep 17 00:00:00 2001 From: derharry333 Date: Sat, 5 Oct 2019 14:37:24 +0200 Subject: [PATCH 016/474] Added server.properties --- src/main/java/envoy/client/EnvoyClient.java | 27 +++++++++++++++++---- src/main/resources/server.properties | 2 ++ 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/server.properties diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index a6f5fb9..50d3bb9 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -1,6 +1,8 @@ package envoy.client; +import java.io.IOException; import java.time.Instant; +import java.util.Properties; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; @@ -27,6 +29,19 @@ public class EnvoyClient { private DatatypeFactory datatypeFactory; + private static final Properties serverProps = new Properties(); + + static { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + try { + serverProps.load(loader.getResourceAsStream("server.properties")); + + } catch (IOException e) { + e.printStackTrace(); + } + + } + public EnvoyClient() { try { datatypeFactory = DatatypeFactory.newInstance(); @@ -58,9 +73,11 @@ public class EnvoyClient { } // Send message - Client client = ClientBuilder.newClient(); - WebTarget target = client.target("http://kske.feste-ip.net:43315/envoy-server/rest/message/send"); - Response response = target.request().post(Entity.entity(message, "application/xml")); + String url = String.format("%s:%s/envoy-server/rest/message/send", serverProps.getProperty("server"), + serverProps.getProperty("port")); + Client client = ClientBuilder.newClient(); + WebTarget target = client.target(url); + Response response = target.request().post(Entity.entity(message, "application/xml")); System.out.println("Response code: " + response.getStatus()); response.close(); client.close(); @@ -76,8 +93,8 @@ public class EnvoyClient { * @return Prepared {@link Message} object */ public Message createMessage(String senderID, String recipientID, String textContent) { - ObjectFactory factory = new ObjectFactory(); - Message.MetaData metaData = factory.createMessageMetaData(); + ObjectFactory factory = new ObjectFactory(); + Message.MetaData metaData = factory.createMessageMetaData(); metaData.setSender(senderID); metaData.setRecipient(recipientID); metaData.setState(false); diff --git a/src/main/resources/server.properties b/src/main/resources/server.properties new file mode 100644 index 0000000..6b0ae8f --- /dev/null +++ b/src/main/resources/server.properties @@ -0,0 +1,2 @@ +server=http://kske.feste-ip.net +port=43315 \ No newline at end of file From a8df45900eb03cf30ce9b72d8c42b3e1bfec679d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 5 Oct 2019 15:07:56 +0200 Subject: [PATCH 017/474] Added support for new message schema --- src/main/java/envoy/client/EnvoyClient.java | 25 +++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index a6f5fb9..41c32d0 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -1,6 +1,7 @@ package envoy.client; import java.time.Instant; +import java.util.Arrays; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; @@ -14,6 +15,7 @@ import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import envoy.schema.Message; +import envoy.schema.Messages; import envoy.schema.ObjectFactory; /** @@ -25,7 +27,8 @@ import envoy.schema.ObjectFactory; public class EnvoyClient { - private DatatypeFactory datatypeFactory; + private ObjectFactory objectFactory = new ObjectFactory(); + private DatatypeFactory datatypeFactory; public EnvoyClient() { try { @@ -46,13 +49,16 @@ public class EnvoyClient { */ public void sendMessage(Message message) { new Thread(() -> { + // Wrap single message into messages list + Messages messages = wrapMessage(message); + // Print message XML to console JAXBContext jc; try { jc = JAXBContext.newInstance("envoy.schema"); Marshaller m = jc.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - m.marshal(message, System.out); + m.marshal(messages, System.out); } catch (JAXBException e) { e.printStackTrace(); } @@ -60,7 +66,7 @@ public class EnvoyClient { // Send message Client client = ClientBuilder.newClient(); WebTarget target = client.target("http://kske.feste-ip.net:43315/envoy-server/rest/message/send"); - Response response = target.request().post(Entity.entity(message, "application/xml")); + Response response = target.request().post(Entity.entity(messages, "application/xml")); System.out.println("Response code: " + response.getStatus()); response.close(); client.close(); @@ -76,21 +82,26 @@ public class EnvoyClient { * @return Prepared {@link Message} object */ public Message createMessage(String senderID, String recipientID, String textContent) { - ObjectFactory factory = new ObjectFactory(); - Message.MetaData metaData = factory.createMessageMetaData(); + Message.MetaData metaData = objectFactory.createMessageMetaData(); metaData.setSender(senderID); metaData.setRecipient(recipientID); metaData.setState(false); metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); - Message.Content content = factory.createMessageContent(); + Message.Content content = objectFactory.createMessageContent(); content.setType("text"); content.setText(textContent); - Message message = factory.createMessage(); + Message message = objectFactory.createMessage(); message.setMetaData(metaData); message.getContent().add(content); return message; } + + public Messages wrapMessage(Message... messages) { + Messages wrapper = objectFactory.createMessages(); + wrapper.getMessage().addAll(Arrays.asList(messages)); + return wrapper; + } } \ No newline at end of file From ab02a783c97c1f3af4796b415683a6d39bf8434b Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 6 Oct 2019 10:41:32 +0200 Subject: [PATCH 018/474] Fixed formatting --- src/main/java/envoy/client/EnvoyClient.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index 50d3bb9..c832ee0 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -39,7 +39,6 @@ public class EnvoyClient { } catch (IOException e) { e.printStackTrace(); } - } public EnvoyClient() { @@ -73,11 +72,12 @@ public class EnvoyClient { } // Send message - String url = String.format("%s:%s/envoy-server/rest/message/send", serverProps.getProperty("server"), + String url = String.format("%s:%s/envoy-server/rest/message/send", + serverProps.getProperty("server"), serverProps.getProperty("port")); - Client client = ClientBuilder.newClient(); - WebTarget target = client.target(url); - Response response = target.request().post(Entity.entity(message, "application/xml")); + Client client = ClientBuilder.newClient(); + WebTarget target = client.target(url); + Response response = target.request().post(Entity.entity(message, "application/xml")); System.out.println("Response code: " + response.getStatus()); response.close(); client.close(); @@ -93,8 +93,8 @@ public class EnvoyClient { * @return Prepared {@link Message} object */ public Message createMessage(String senderID, String recipientID, String textContent) { - ObjectFactory factory = new ObjectFactory(); - Message.MetaData metaData = factory.createMessageMetaData(); + ObjectFactory factory = new ObjectFactory(); + Message.MetaData metaData = factory.createMessageMetaData(); metaData.setSender(senderID); metaData.setRecipient(recipientID); metaData.setState(false); From ff175ca219848dd848108f4f8a3a43a377ea359a Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 6 Oct 2019 13:30:31 +0200 Subject: [PATCH 019/474] Fixed compile error caused by missing import declaration --- src/main/java/envoy/client/EnvoyClient.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index 38b7248..e97a9e4 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -2,6 +2,7 @@ package envoy.client; import java.io.IOException; import java.time.Instant; +import java.util.Arrays; import java.util.Properties; import javax.ws.rs.client.Client; From 8b036021abb3a62702700e31f3e732ea6e710703 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 6 Oct 2019 13:33:23 +0200 Subject: [PATCH 020/474] Fixed runtime error related to XML marshaling --- src/main/java/envoy/client/EnvoyClient.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index e97a9e4..c659c4e 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -78,12 +78,11 @@ public class EnvoyClient { } // Send message - String url = String.format("%s:%s/envoy-server/rest/message/send", - serverProps.getProperty("server"), - serverProps.getProperty("port")); Client client = ClientBuilder.newClient(); - WebTarget target = client.target(url); - Response response = target.request().post(Entity.entity(message, "application/xml")); + WebTarget target = client.target(String.format("%s:%s/envoy-server/rest/message/send", + serverProps.getProperty("server"), + serverProps.getProperty("port"))); + Response response = target.request().post(Entity.entity(messages, "application/xml")); System.out.println("Response code: " + response.getStatus()); response.close(); client.close(); From 4dcb1ce3666671bbc868d867b2c9062d55d36430 Mon Sep 17 00:00:00 2001 From: Maxi Date: Mon, 7 Oct 2019 16:14:14 +0200 Subject: [PATCH 021/474] Added user list download --- src/main/java/envoy/client/EnvoyClient.java | 63 +++++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 105 +++++++++++++----- 2 files changed, 139 insertions(+), 29 deletions(-) diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index c659c4e..5380aed 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -1,8 +1,12 @@ package envoy.client; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StringReader; import java.time.Instant; import java.util.Arrays; +import java.util.List; import java.util.Properties; import javax.ws.rs.client.Client; @@ -15,9 +19,27 @@ import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.util.EntityUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import envoy.client.ui.ChatWindow; import envoy.schema.Message; import envoy.schema.Messages; +import envoy.schema.User; +import envoy.schema.Users; import envoy.schema.ObjectFactory; /** @@ -29,6 +51,7 @@ import envoy.schema.ObjectFactory; public class EnvoyClient { + ChatWindow chatWindow = new ChatWindow(); private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; @@ -120,4 +143,44 @@ public class EnvoyClient { wrapper.getMessage().addAll(Arrays.asList(messages)); return wrapper; } + + public void getUsersListXml () throws ClientProtocolException, IOException, SAXException, ParserConfigurationException { + + /*HttpClient client = new DefaultHttpClient(); + HttpGet request = new HttpGet(String.format("%s:%s/envoy-server/rest/user", + serverProps.getProperty("server"), + serverProps.getProperty("port"))); + HttpResponse response = client.execute(request); + + BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); + System.out.println(rd.readLine()); + + String inputLine; + StringBuffer response1 = new StringBuffer(); + while((inputLine = rd.readLine()) != null) { + response1.append(inputLine); + } + */ + + Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() + .parse(String.format("%s:%s/envoy-server/rest/user", + serverProps.getProperty("server"), + serverProps.getProperty("port"))); + NodeList errNodes = doc.getElementsByTagName("User"); + + for (int i = 0; i < errNodes.getLength(); i++) { + if(errNodes.getLength() > 0) { + Element err = (Element)errNodes.item(i); + //System.out.println("Name: " + err.getElementsByTagName("Name").item(0).getTextContent()); + //System.out.println("Id: " + err.getElementsByTagName("ID").item(0).getTextContent()); + User user = new User(); + user.setName(err.getElementsByTagName("Name").item(0).getTextContent()); + user.setID(Long.parseLong(err.getElementsByTagName("ID").item(0).getTextContent())); + chatWindow.addUserToList(user); + + } + } + chatWindow.printUserListElements(); + chatWindow.loadUserJList(); + } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 8fb801e..056a4c5 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -7,6 +7,9 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.awt.List; +import java.io.IOException; +import java.util.ArrayList; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -17,9 +20,14 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.border.EmptyBorder; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.http.client.ClientProtocolException; +import org.xml.sax.SAXException; import envoy.client.EnvoyClient; import envoy.schema.Message; +import envoy.schema.User; /** * Project: envoy-client
@@ -31,11 +39,13 @@ public class ChatWindow extends JFrame { private static final long serialVersionUID = 6865098428255463649L; - private JPanel contentPane = new JPanel(); - private EnvoyClient envoyClient = new EnvoyClient(); + private JPanel contentPane = new JPanel(); + private static EnvoyClient envoyClient = new EnvoyClient(); public DefaultListModel listModel = new DefaultListModel<>(); + public ArrayList userList = new ArrayList(); + public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); @@ -47,10 +57,10 @@ public class ChatWindow extends JFrame { contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); GridBagLayout gbl_contentPane = new GridBagLayout(); - gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; - gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; - gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; - gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; + gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; + gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; + gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; + gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; contentPane.setLayout(gbl_contentPane); JList elementList = new JList<>(); @@ -74,10 +84,10 @@ public class ChatWindow extends JFrame { scrollPane.setBorder(null); GridBagConstraints gbc_scrollPane = new GridBagConstraints(); - gbc_scrollPane.fill = GridBagConstraints.BOTH; - gbc_scrollPane.gridwidth = 2; - gbc_scrollPane.gridx = 1; - gbc_scrollPane.gridy = 1; + gbc_scrollPane.fill = GridBagConstraints.BOTH; + gbc_scrollPane.gridwidth = 2; + gbc_scrollPane.gridx = 1; + gbc_scrollPane.gridy = 1; gbc_scrollPane.insets = new Insets(10, 10, 10, 10); @@ -94,9 +104,9 @@ public class ChatWindow extends JFrame { messageEnterTextfield.setBorder(new EmptyBorder(5, 5, 5, 5)); GridBagConstraints gbc_moveSelectionMessageEnterTextfield = new GridBagConstraints(); - gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; - gbc_moveSelectionMessageEnterTextfield.gridx = 1; - gbc_moveSelectionMessageEnterTextfield.gridy = 2; + gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; + gbc_moveSelectionMessageEnterTextfield.gridx = 1; + gbc_moveSelectionMessageEnterTextfield.gridy = 2; gbc_moveSelectionMessageEnterTextfield.insets = new Insets(10, 10, 10, 10); @@ -110,28 +120,50 @@ public class ChatWindow extends JFrame { GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); - gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; - gbc_moveSelectionPostButton.gridx = 2; - gbc_moveSelectionPostButton.gridy = 2; + gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; + gbc_moveSelectionPostButton.gridx = 2; + gbc_moveSelectionPostButton.gridy = 2; gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); contentPane.add(postButton, gbc_moveSelectionPostButton); postButton.addActionListener((evt) -> { - if (!messageEnterTextfield.getText().isEmpty()) try { - final Message message = envoyClient.createMessage("Kai", "Maxi", messageEnterTextfield.getText()); - envoyClient.sendMessage(message); - appendMessageToChat(message); - messageEnterTextfield.setText(""); - } catch (Exception e) { - JOptionPane.showMessageDialog(this, - "An exception occured while sending a message. See the log for more details.", - "Exception occured", - JOptionPane.ERROR_MESSAGE); - e.printStackTrace(); - } + if (!messageEnterTextfield.getText().isEmpty()) + try { + final Message message = envoyClient.createMessage("Kai", "Maxi", messageEnterTextfield.getText()); + envoyClient.sendMessage(message); + appendMessageToChat(message); + messageEnterTextfield.setText(""); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "An exception occured while sending a message. See the log for more details.", + "Exception occured", JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } }); + + } + + public void loadUserJList() { + // User List + JList userJList = new JList<>(); + DefaultListModel userJListModel = new DefaultListModel<>(); + for (int i = 0; i < userList.size(); i++) { + userJListModel.addElement(userList.get(i)); + } + userJList.setModel(userJListModel); + + GridBagConstraints gbc_userList = new GridBagConstraints(); + gbc_userList.fill = GridBagConstraints.BOTH; + gbc_userList.gridx = 0; + gbc_userList.gridy = 1; + + // gbc_userList.insets = new Insets(10, 10, 10, 10); + System.out.println(userJListModel.getSize()); + System.out.println("test"); + + contentPane.add(userJList, gbc_userList); } /** @@ -155,7 +187,20 @@ public class ChatWindow extends JFrame { + ""); } - public static void main(String[] args) { + public void addUserToList(User user) { + userList.add(user); + + } + + public void printUserListElements() { + for (int i = 0; i < userList.size(); i++) { + System.out.println(userList.get(i).getName()); + System.out.println(userList.get(i).getID()); + } + } + + public static void main(String[] args) + throws ClientProtocolException, IOException, SAXException, ParserConfigurationException { EventQueue.invokeLater(() -> { try { ChatWindow frame = new ChatWindow(); @@ -164,5 +209,7 @@ public class ChatWindow extends JFrame { e.printStackTrace(); } }); + envoyClient.getUsersListXml(); + System.out.println("asd"); } } \ No newline at end of file From d64e3af79d005c02976fc61c7440f3c22eb05fb7 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 7 Oct 2019 17:35:57 +0200 Subject: [PATCH 022/474] Using JAX-RS to retrieve user list --- src/main/java/envoy/client/EnvoyClient.java | 69 ++--------- src/main/java/envoy/client/ui/ChatWindow.java | 114 ++++++++---------- 2 files changed, 60 insertions(+), 123 deletions(-) diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index 5380aed..5d9dca4 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -1,12 +1,8 @@ package envoy.client; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.StringReader; import java.time.Instant; import java.util.Arrays; -import java.util.List; import java.util.Properties; import javax.ws.rs.client.Client; @@ -19,28 +15,12 @@ import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.util.EntityUtils; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; import envoy.client.ui.ChatWindow; import envoy.schema.Message; import envoy.schema.Messages; -import envoy.schema.User; -import envoy.schema.Users; import envoy.schema.ObjectFactory; +import envoy.schema.Users; /** * Project: envoy-client
@@ -51,7 +31,7 @@ import envoy.schema.ObjectFactory; public class EnvoyClient { - ChatWindow chatWindow = new ChatWindow(); + ChatWindow chatWindow = new ChatWindow(); private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; @@ -143,44 +123,17 @@ public class EnvoyClient { wrapper.getMessage().addAll(Arrays.asList(messages)); return wrapper; } - - public void getUsersListXml () throws ClientProtocolException, IOException, SAXException, ParserConfigurationException { - /*HttpClient client = new DefaultHttpClient(); - HttpGet request = new HttpGet(String.format("%s:%s/envoy-server/rest/user", + public Users getUsersListXml() { + Client client = ClientBuilder.newClient(); + WebTarget target = client.target(String.format("%s:%s/envoy-server/rest/user", serverProps.getProperty("server"), serverProps.getProperty("port"))); - HttpResponse response = client.execute(request); - - BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); - System.out.println(rd.readLine()); - - String inputLine; - StringBuffer response1 = new StringBuffer(); - while((inputLine = rd.readLine()) != null) { - response1.append(inputLine); - } - */ - - Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() - .parse(String.format("%s:%s/envoy-server/rest/user", - serverProps.getProperty("server"), - serverProps.getProperty("port"))); - NodeList errNodes = doc.getElementsByTagName("User"); - - for (int i = 0; i < errNodes.getLength(); i++) { - if(errNodes.getLength() > 0) { - Element err = (Element)errNodes.item(i); - //System.out.println("Name: " + err.getElementsByTagName("Name").item(0).getTextContent()); - //System.out.println("Id: " + err.getElementsByTagName("ID").item(0).getTextContent()); - User user = new User(); - user.setName(err.getElementsByTagName("Name").item(0).getTextContent()); - user.setID(Long.parseLong(err.getElementsByTagName("ID").item(0).getTextContent())); - chatWindow.addUserToList(user); - - } - } - chatWindow.printUserListElements(); - chatWindow.loadUserJList(); + Response response = target.request("application/xml").get(); + Users users = response.readEntity(Users.class); + System.out.println("Response code: " + response.getStatus()); + response.close(); + client.close(); + return users; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 056a4c5..2398e52 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -7,9 +7,7 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; -import java.awt.List; import java.io.IOException; -import java.util.ArrayList; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -19,6 +17,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; +import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.xml.parsers.ParserConfigurationException; @@ -28,6 +27,7 @@ import org.xml.sax.SAXException; import envoy.client.EnvoyClient; import envoy.schema.Message; import envoy.schema.User; +import envoy.schema.Users; /** * Project: envoy-client
@@ -39,13 +39,11 @@ public class ChatWindow extends JFrame { private static final long serialVersionUID = 6865098428255463649L; - private JPanel contentPane = new JPanel(); - private static EnvoyClient envoyClient = new EnvoyClient(); + private JPanel contentPane = new JPanel(); + private static EnvoyClient envoyClient = new EnvoyClient(); public DefaultListModel listModel = new DefaultListModel<>(); - public ArrayList userList = new ArrayList(); - public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); @@ -57,10 +55,10 @@ public class ChatWindow extends JFrame { contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); GridBagLayout gbl_contentPane = new GridBagLayout(); - gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; - gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; - gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; - gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; + gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; + gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; + gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; + gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; contentPane.setLayout(gbl_contentPane); JList elementList = new JList<>(); @@ -84,10 +82,10 @@ public class ChatWindow extends JFrame { scrollPane.setBorder(null); GridBagConstraints gbc_scrollPane = new GridBagConstraints(); - gbc_scrollPane.fill = GridBagConstraints.BOTH; - gbc_scrollPane.gridwidth = 2; - gbc_scrollPane.gridx = 1; - gbc_scrollPane.gridy = 1; + gbc_scrollPane.fill = GridBagConstraints.BOTH; + gbc_scrollPane.gridwidth = 2; + gbc_scrollPane.gridx = 1; + gbc_scrollPane.gridy = 1; gbc_scrollPane.insets = new Insets(10, 10, 10, 10); @@ -104,9 +102,9 @@ public class ChatWindow extends JFrame { messageEnterTextfield.setBorder(new EmptyBorder(5, 5, 5, 5)); GridBagConstraints gbc_moveSelectionMessageEnterTextfield = new GridBagConstraints(); - gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; - gbc_moveSelectionMessageEnterTextfield.gridx = 1; - gbc_moveSelectionMessageEnterTextfield.gridy = 2; + gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; + gbc_moveSelectionMessageEnterTextfield.gridx = 1; + gbc_moveSelectionMessageEnterTextfield.gridy = 2; gbc_moveSelectionMessageEnterTextfield.insets = new Insets(10, 10, 10, 10); @@ -120,50 +118,52 @@ public class ChatWindow extends JFrame { GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); - gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; - gbc_moveSelectionPostButton.gridx = 2; - gbc_moveSelectionPostButton.gridy = 2; + gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; + gbc_moveSelectionPostButton.gridx = 2; + gbc_moveSelectionPostButton.gridy = 2; gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); contentPane.add(postButton, gbc_moveSelectionPostButton); postButton.addActionListener((evt) -> { - if (!messageEnterTextfield.getText().isEmpty()) - try { - final Message message = envoyClient.createMessage("Kai", "Maxi", messageEnterTextfield.getText()); - envoyClient.sendMessage(message); - appendMessageToChat(message); - messageEnterTextfield.setText(""); - } catch (Exception e) { - JOptionPane.showMessageDialog(this, - "An exception occured while sending a message. See the log for more details.", - "Exception occured", JOptionPane.ERROR_MESSAGE); - e.printStackTrace(); - } + if (!messageEnterTextfield.getText().isEmpty()) try { + final Message message = envoyClient.createMessage("Kai", "Maxi", messageEnterTextfield.getText()); + envoyClient.sendMessage(message); + appendMessageToChat(message); + messageEnterTextfield.setText(""); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "An exception occured while sending a message. See the log for more details.", + "Exception occured", + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } }); - + new Thread(() -> loadUserJList()).start(); } public void loadUserJList() { - // User List - JList userJList = new JList<>(); - DefaultListModel userJListModel = new DefaultListModel<>(); - for (int i = 0; i < userList.size(); i++) { - userJListModel.addElement(userList.get(i)); - } - userJList.setModel(userJListModel); + Users users = envoyClient.getUsersListXml(); - GridBagConstraints gbc_userList = new GridBagConstraints(); - gbc_userList.fill = GridBagConstraints.BOTH; - gbc_userList.gridx = 0; - gbc_userList.gridy = 1; + SwingUtilities.invokeLater(() -> { + // User List + JList userJList = new JList<>(); + DefaultListModel userJListModel = new DefaultListModel<>(); + users.getUser().forEach(user -> userJListModel.addElement(user)); + userJList.setModel(userJListModel); - // gbc_userList.insets = new Insets(10, 10, 10, 10); - System.out.println(userJListModel.getSize()); - System.out.println("test"); + GridBagConstraints gbc_userList = new GridBagConstraints(); + gbc_userList.fill = GridBagConstraints.BOTH; + gbc_userList.gridx = 0; + gbc_userList.gridy = 1; - contentPane.add(userJList, gbc_userList); + // gbc_userList.insets = new Insets(10, 10, 10, 10); + System.out.println(userJListModel.getSize()); + System.out.println("test"); + + contentPane.add(userJList, gbc_userList); + }); } /** @@ -172,9 +172,7 @@ public class ChatWindow extends JFrame { * @param message The message from which to return the text content * @return The first content of type 'text' */ - public String getFirstTextContent(Message message) { - return message.getContent().get(0).getText(); - } + public String getFirstTextContent(Message message) { return message.getContent().get(0).getText(); } /** * Appends a message with sender and message content to the message list. @@ -187,18 +185,6 @@ public class ChatWindow extends JFrame { + ""); } - public void addUserToList(User user) { - userList.add(user); - - } - - public void printUserListElements() { - for (int i = 0; i < userList.size(); i++) { - System.out.println(userList.get(i).getName()); - System.out.println(userList.get(i).getID()); - } - } - public static void main(String[] args) throws ClientProtocolException, IOException, SAXException, ParserConfigurationException { EventQueue.invokeLater(() -> { @@ -209,7 +195,5 @@ public class ChatWindow extends JFrame { e.printStackTrace(); } }); - envoyClient.getUsersListXml(); - System.out.println("asd"); } } \ No newline at end of file From 4b449cef4552992b9d12cc13469031568d122cdb Mon Sep 17 00:00:00 2001 From: Maxi Date: Wed, 9 Oct 2019 21:54:31 +0200 Subject: [PATCH 023/474] Added user list (abstractListModel), setting the recipientID (in message object) by selecting user from the list. --- src/main/java/envoy/client/EnvoyClient.java | 5 +- src/main/java/envoy/client/ui/ChatWindow.java | 67 ++++++++++++++++--- .../java/envoy/client/ui/UserJListModel.java | 38 +++++++++++ 3 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 src/main/java/envoy/client/ui/UserJListModel.java diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index 5d9dca4..8b368b5 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -85,6 +85,7 @@ public class EnvoyClient { WebTarget target = client.target(String.format("%s:%s/envoy-server/rest/message/send", serverProps.getProperty("server"), serverProps.getProperty("port"))); + Response response = target.request().post(Entity.entity(messages, "application/xml")); System.out.println("Response code: " + response.getStatus()); response.close(); @@ -100,7 +101,7 @@ public class EnvoyClient { * @param textContent The content (text) of the message * @return Prepared {@link Message} object */ - public Message createMessage(String senderID, String recipientID, String textContent) { + public Message createMessage(String senderID, long recipientID, String textContent) { Message.MetaData metaData = objectFactory.createMessageMetaData(); metaData.setSender(senderID); metaData.setRecipient(recipientID); @@ -123,7 +124,7 @@ public class EnvoyClient { wrapper.getMessage().addAll(Arrays.asList(messages)); return wrapper; } - + public Users getUsersListXml() { Client client = ClientBuilder.newClient(); WebTarget target = client.target(String.format("%s:%s/envoy-server/rest/user", diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 2398e52..af0db13 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -7,8 +7,10 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.awt.List; import java.io.IOException; +import javax.swing.AbstractListModel; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JFrame; @@ -17,8 +19,11 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; +import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; import javax.xml.parsers.ParserConfigurationException; import org.apache.http.client.ClientProtocolException; @@ -37,10 +42,13 @@ import envoy.schema.Users; */ public class ChatWindow extends JFrame { + private static final long serialVersionUID = 6865098428255463649L; + public long recipientID = 0; private JPanel contentPane = new JPanel(); private static EnvoyClient envoyClient = new EnvoyClient(); + private static UserJListModel AuserJListModel = new UserJListModel(); public DefaultListModel listModel = new DefaultListModel<>(); @@ -115,6 +123,7 @@ public class ChatWindow extends JFrame { postButton.setForeground(new Color(255, 255, 255)); postButton.setBackground(new Color(102, 51, 153)); postButton.setBorderPainted(false); + GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); @@ -127,8 +136,11 @@ public class ChatWindow extends JFrame { contentPane.add(postButton, gbc_moveSelectionPostButton); postButton.addActionListener((evt) -> { - if (!messageEnterTextfield.getText().isEmpty()) try { - final Message message = envoyClient.createMessage("Kai", "Maxi", messageEnterTextfield.getText()); + if(recipientID == 0) + System.out.println("Please select recipient"); + + if (!messageEnterTextfield.getText().isEmpty() && recipientID != 0) try { + final Message message = envoyClient.createMessage("Kai", recipientID, messageEnterTextfield.getText()); envoyClient.sendMessage(message); appendMessageToChat(message); messageEnterTextfield.setText(""); @@ -140,29 +152,62 @@ public class ChatWindow extends JFrame { e.printStackTrace(); } }); + new Thread(() -> loadUserJList()).start(); + } - + public void loadUserJList() { - Users users = envoyClient.getUsersListXml(); + //Users users = envoyClient.getUsersListXml(); + SwingUtilities.invokeLater(() -> { + // User List JList userJList = new JList<>(); - DefaultListModel userJListModel = new DefaultListModel<>(); - users.getUser().forEach(user -> userJListModel.addElement(user)); - userJList.setModel(userJListModel); + + //System.out.println(userJListModel.getElementAt(0).getName()); + userJList.setModel(AuserJListModel); + + userJList.setSelectionForeground(new Color(255, 255, 255)); + userJList.setSelectionBackground(new Color(102, 0, 153)); + userJList.setForeground(new Color(255, 255, 255)); + userJList.setBackground(new Color(51, 51, 51)); + userJList.setFont(new Font("Arial", Font.PLAIN, 17)); + //userJList.setFixedCellHeight(60); + userJList.setBorder(new EmptyBorder(5, 5, 5, 5)); GridBagConstraints gbc_userList = new GridBagConstraints(); - gbc_userList.fill = GridBagConstraints.BOTH; + //gbc_userList.fill = GridBagConstraints.BOTH; gbc_userList.gridx = 0; gbc_userList.gridy = 1; + gbc_userList.anchor = GridBagConstraints.PAGE_START; - // gbc_userList.insets = new Insets(10, 10, 10, 10); - System.out.println(userJListModel.getSize()); - System.out.println("test"); + gbc_userList.insets = new Insets(10, 0, 10, 0); + //System.out.println(userJListModel.getSize()); + //System.out.println("test"); + + userJList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + ListSelectionListener listSelectionListener = new ListSelectionListener() { + + @Override + public void valueChanged(ListSelectionEvent listSelectionEvent) {; + boolean adjust = listSelectionEvent.getValueIsAdjusting(); + if (!adjust) { + JList selectedUserList = (JList) listSelectionEvent.getSource(); + int selection = selectedUserList.getSelectedIndex(); + + //System.out.println(AuserJListModel.getElementID(selection)); + recipientID = AuserJListModel.getElementID(selection); + } + } + + }; + userJList.addListSelectionListener(listSelectionListener); contentPane.add(userJList, gbc_userList); + + contentPane.revalidate(); }); } diff --git a/src/main/java/envoy/client/ui/UserJListModel.java b/src/main/java/envoy/client/ui/UserJListModel.java new file mode 100644 index 0000000..05473e9 --- /dev/null +++ b/src/main/java/envoy/client/ui/UserJListModel.java @@ -0,0 +1,38 @@ +package envoy.client.ui; + +import java.util.*; +import java.util.LinkedList; + +import javax.swing.AbstractListModel; + +import envoy.client.EnvoyClient; +import envoy.schema.User; +import envoy.schema.Users; + +public class UserJListModel extends AbstractListModel { + + public EnvoyClient envoyClient = new EnvoyClient(); + Users users = envoyClient.getUsersListXml(); + private List userList = new LinkedList<>(); + + public UserJListModel() { + users.getUser().forEach(user -> userList.add(user)); + } + + + @Override + public int getSize() { + return userList.size(); + } + + @Override + public Object getElementAt(int index) { + return userList.get(index).getName(); + } + + public long getElementID(int index) { + return userList.get(index).getID(); + } + + +} From f840419345abc0e9040235d65a0a266bc2b74ae7 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 12 Oct 2019 08:19:00 +0200 Subject: [PATCH 024/474] Replaces AbstractListModel with ListCellRenderer, optimized threading --- src/main/java/envoy/client/EnvoyClient.java | 12 +- src/main/java/envoy/client/ui/ChatWindow.java | 127 +++++++----------- .../java/envoy/client/ui/UserJListModel.java | 38 ------ .../envoy/client/ui/UserListRenderer.java | 41 ++++++ 4 files changed, 100 insertions(+), 118 deletions(-) delete mode 100644 src/main/java/envoy/client/ui/UserJListModel.java create mode 100644 src/main/java/envoy/client/ui/UserListRenderer.java diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/EnvoyClient.java index 8b368b5..7bef3e5 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/EnvoyClient.java @@ -16,8 +16,8 @@ import javax.xml.bind.Marshaller; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; -import envoy.client.ui.ChatWindow; import envoy.schema.Message; +import envoy.schema.Message.MetaData.MessageState; import envoy.schema.Messages; import envoy.schema.ObjectFactory; import envoy.schema.Users; @@ -26,12 +26,14 @@ import envoy.schema.Users; * Project: envoy-client
* File: EnvoyClient.java
* Created: 28 Sep 2019
- * Author: Kai S. K. Engelbart & Maximilian Käfer + * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy 0.1 */ public class EnvoyClient { - ChatWindow chatWindow = new ChatWindow(); private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; @@ -101,11 +103,11 @@ public class EnvoyClient { * @param textContent The content (text) of the message * @return Prepared {@link Message} object */ - public Message createMessage(String senderID, long recipientID, String textContent) { + public Message createMessage(long senderID, long recipientID, String textContent) { Message.MetaData metaData = objectFactory.createMessageMetaData(); metaData.setSender(senderID); metaData.setRecipient(recipientID); - metaData.setState(false); + metaData.setState(MessageState.WAITING); metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); Message.Content content = objectFactory.createMessageContent(); diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index af0db13..1b5768a 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -7,10 +7,8 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; -import java.awt.List; import java.io.IOException; -import javax.swing.AbstractListModel; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JFrame; @@ -22,8 +20,6 @@ import javax.swing.JTextArea; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import javax.xml.parsers.ParserConfigurationException; import org.apache.http.client.ClientProtocolException; @@ -38,19 +34,20 @@ import envoy.schema.Users; * Project: envoy-client
* File: ChatWindow.java
* Created: 28 Sep 2019
- * Author: Maximilian Käfer & Kai S. K. Engelbart + * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy 0.1 */ public class ChatWindow extends JFrame { - private static final long serialVersionUID = 6865098428255463649L; - public long recipientID = 0; - private JPanel contentPane = new JPanel(); - private static EnvoyClient envoyClient = new EnvoyClient(); - private static UserJListModel AuserJListModel = new UserJListModel(); + private long recipientID = 0; + private JPanel contentPane = new JPanel(); + private EnvoyClient envoyClient = new EnvoyClient(); - public DefaultListModel listModel = new DefaultListModel<>(); + private DefaultListModel messageListModel = new DefaultListModel<>(); public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -78,7 +75,7 @@ public class ChatWindow extends JFrame { elementList.setForeground(new Color(255, 255, 255)); elementList.setBackground(new Color(51, 51, 51)); - elementList.setModel(listModel); + elementList.setModel(messageListModel); elementList.setFont(new Font("Arial", Font.PLAIN, 17)); elementList.setFixedCellHeight(60); elementList.setBorder(new EmptyBorder(5, 5, 5, 5)); @@ -123,7 +120,6 @@ public class ChatWindow extends JFrame { postButton.setForeground(new Color(255, 255, 255)); postButton.setBackground(new Color(102, 51, 153)); postButton.setBorderPainted(false); - GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); @@ -136,11 +132,11 @@ public class ChatWindow extends JFrame { contentPane.add(postButton, gbc_moveSelectionPostButton); postButton.addActionListener((evt) -> { - if(recipientID == 0) - System.out.println("Please select recipient"); - + if (recipientID == 0) System.out.println("Please select recipient"); + + // TODO: Acquire proper sender id if (!messageEnterTextfield.getText().isEmpty() && recipientID != 0) try { - final Message message = envoyClient.createMessage("Kai", recipientID, messageEnterTextfield.getText()); + final Message message = envoyClient.createMessage(1, recipientID, messageEnterTextfield.getText()); envoyClient.sendMessage(message); appendMessageToChat(message); messageEnterTextfield.setText(""); @@ -152,63 +148,44 @@ public class ChatWindow extends JFrame { e.printStackTrace(); } }); - - new Thread(() -> loadUserJList()).start(); - - } - - public void loadUserJList() { - //Users users = envoyClient.getUsersListXml(); - - SwingUtilities.invokeLater(() -> { - - // User List - JList userJList = new JList<>(); - - //System.out.println(userJListModel.getElementAt(0).getName()); - userJList.setModel(AuserJListModel); - - userJList.setSelectionForeground(new Color(255, 255, 255)); - userJList.setSelectionBackground(new Color(102, 0, 153)); - userJList.setForeground(new Color(255, 255, 255)); - userJList.setBackground(new Color(51, 51, 51)); - userJList.setFont(new Font("Arial", Font.PLAIN, 17)); - //userJList.setFixedCellHeight(60); - userJList.setBorder(new EmptyBorder(5, 5, 5, 5)); - - GridBagConstraints gbc_userList = new GridBagConstraints(); - //gbc_userList.fill = GridBagConstraints.BOTH; - gbc_userList.gridx = 0; - gbc_userList.gridy = 1; - gbc_userList.anchor = GridBagConstraints.PAGE_START; - - gbc_userList.insets = new Insets(10, 0, 10, 0); - //System.out.println(userJListModel.getSize()); - //System.out.println("test"); - - - userJList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - ListSelectionListener listSelectionListener = new ListSelectionListener() { - - @Override - public void valueChanged(ListSelectionEvent listSelectionEvent) {; - boolean adjust = listSelectionEvent.getValueIsAdjusting(); - if (!adjust) { - JList selectedUserList = (JList) listSelectionEvent.getSource(); - int selection = selectedUserList.getSelectedIndex(); - - //System.out.println(AuserJListModel.getElementID(selection)); - recipientID = AuserJListModel.getElementID(selection); - } - } - - }; - userJList.addListSelectionListener(listSelectionListener); - contentPane.add(userJList, gbc_userList); - - contentPane.revalidate(); + JList userList = new JList<>(); + userList.setCellRenderer(new UserListRenderer()); + userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + userList.addListSelectionListener((listSelectionEvent) -> { + if (!listSelectionEvent.getValueIsAdjusting()) { + @SuppressWarnings("unchecked") + JList selectedUserList = (JList) listSelectionEvent.getSource(); + recipientID = selectedUserList.getModel().getElementAt(selectedUserList.getSelectedIndex()).getID(); + } }); + + userList.setSelectionForeground(new Color(255, 255, 255)); + userList.setSelectionBackground(new Color(102, 0, 153)); + userList.setForeground(new Color(255, 255, 255)); + userList.setBackground(new Color(51, 51, 51)); + userList.setFont(new Font("Arial", Font.PLAIN, 17)); + userList.setBorder(new EmptyBorder(5, 5, 5, 5)); + + GridBagConstraints gbc_userList = new GridBagConstraints(); + gbc_userList.gridx = 0; + gbc_userList.gridy = 1; + gbc_userList.anchor = GridBagConstraints.PAGE_START; + gbc_userList.insets = new Insets(10, 0, 10, 0); + + contentPane.add(userList, gbc_userList); + contentPane.revalidate(); + + loadUserList(userList); + } + + private void loadUserList(JList userList) { + new Thread(() -> { + Users users = envoyClient.getUsersListXml(); + DefaultListModel userListModel = new DefaultListModel<>(); + users.getUser().forEach(user -> userListModel.addElement(user)); + SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); + }).start(); } /** @@ -225,9 +202,9 @@ public class ChatWindow extends JFrame { * @param message The message to append */ private void appendMessageToChat(Message message) { - listModel.addElement("" + "

" + message.getMetaData().getSender() - + " " + "
" + "

" + getFirstTextContent(message) - + ""); + messageListModel.addElement("" + "

" + + message.getMetaData().getSender() + " " + "
" + "

" + + getFirstTextContent(message) + ""); } public static void main(String[] args) diff --git a/src/main/java/envoy/client/ui/UserJListModel.java b/src/main/java/envoy/client/ui/UserJListModel.java deleted file mode 100644 index 05473e9..0000000 --- a/src/main/java/envoy/client/ui/UserJListModel.java +++ /dev/null @@ -1,38 +0,0 @@ -package envoy.client.ui; - -import java.util.*; -import java.util.LinkedList; - -import javax.swing.AbstractListModel; - -import envoy.client.EnvoyClient; -import envoy.schema.User; -import envoy.schema.Users; - -public class UserJListModel extends AbstractListModel { - - public EnvoyClient envoyClient = new EnvoyClient(); - Users users = envoyClient.getUsersListXml(); - private List userList = new LinkedList<>(); - - public UserJListModel() { - users.getUser().forEach(user -> userList.add(user)); - } - - - @Override - public int getSize() { - return userList.size(); - } - - @Override - public Object getElementAt(int index) { - return userList.get(index).getName(); - } - - public long getElementID(int index) { - return userList.get(index).getID(); - } - - -} diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java new file mode 100644 index 0000000..3c62e48 --- /dev/null +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -0,0 +1,41 @@ +package envoy.client.ui; + +import java.awt.Component; + +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +import envoy.schema.User; + +/** + * Project: envoy-client
+ * File: UserListRenderer.java
+ * Created: 12 Oct 2019
+ * + * @author Kai S. K. Engelbart + */ +public class UserListRenderer extends JLabel implements ListCellRenderer { + + private static final long serialVersionUID = 5164417379767181198L; + + @Override + public Component getListCellRendererComponent(JList list, User value, int index, boolean isSelected, + boolean cellHasFocus) { + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + // Enable background rendering + setOpaque(true); + + setText(value.getName()); + setFont(list.getFont()); + + return this; + } +} From 674389f83eca6a84e8b34831a50ce2a698ed5e7e Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 12 Oct 2019 08:24:15 +0200 Subject: [PATCH 025/474] Added Javadoc, changed getFirstTextContent from public to private --- src/main/java/envoy/client/ui/ChatWindow.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 1b5768a..178c738 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -179,6 +179,12 @@ public class ChatWindow extends JFrame { loadUserList(userList); } + /** + * Initializes the elements of the user list by downloading them from the + * server. + * + * @param userList The {@link JList} to put the elements in + */ private void loadUserList(JList userList) { new Thread(() -> { Users users = envoyClient.getUsersListXml(); @@ -194,7 +200,7 @@ public class ChatWindow extends JFrame { * @param message The message from which to return the text content * @return The first content of type 'text' */ - public String getFirstTextContent(Message message) { return message.getContent().get(0).getText(); } + private String getFirstTextContent(Message message) { return message.getContent().get(0).getText(); } /** * Appends a message with sender and message content to the message list. From 68aca9d0ab557638c0e5d7282a96914cef5caaca Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 12 Oct 2019 11:19:29 +0200 Subject: [PATCH 026/474] Renamed EnvoyClient to Client, added Config class --- .../client/{EnvoyClient.java => Client.java} | 47 +++++++------------ src/main/java/envoy/client/Config.java | 46 ++++++++++++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 45 +++++++++++++----- 3 files changed, 94 insertions(+), 44 deletions(-) rename src/main/java/envoy/client/{EnvoyClient.java => Client.java} (74%) create mode 100644 src/main/java/envoy/client/Config.java diff --git a/src/main/java/envoy/client/EnvoyClient.java b/src/main/java/envoy/client/Client.java similarity index 74% rename from src/main/java/envoy/client/EnvoyClient.java rename to src/main/java/envoy/client/Client.java index 7bef3e5..f302a39 100644 --- a/src/main/java/envoy/client/EnvoyClient.java +++ b/src/main/java/envoy/client/Client.java @@ -1,11 +1,8 @@ package envoy.client; -import java.io.IOException; import java.time.Instant; import java.util.Arrays; -import java.util.Properties; -import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; @@ -24,7 +21,7 @@ import envoy.schema.Users; /** * Project: envoy-client
- * File: EnvoyClient.java
+ * File: Client.java
* Created: 28 Sep 2019
* * @author Kai S. K. Engelbart @@ -32,24 +29,14 @@ import envoy.schema.Users; * @since Envoy 0.1 */ -public class EnvoyClient { +public class Client { private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; + private Config config; - private static final Properties serverProps = new Properties(); - - static { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - try { - serverProps.load(loader.getResourceAsStream("server.properties")); - - } catch (IOException e) { - e.printStackTrace(); - } - } - - public EnvoyClient() { + public Client(Config config) { + this.config = config; try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException e) { @@ -83,12 +70,11 @@ public class EnvoyClient { } // Send message - Client client = ClientBuilder.newClient(); - WebTarget target = client.target(String.format("%s:%s/envoy-server/rest/message/send", - serverProps.getProperty("server"), - serverProps.getProperty("port"))); - - Response response = target.request().post(Entity.entity(messages, "application/xml")); + javax.ws.rs.client.Client client = ClientBuilder.newClient(); + WebTarget target = client + .target(String.format("%s:%d/envoy-server/rest/message/send", config.getServer(), config.getPort())); + + Response response = target.request().post(Entity.entity(messages, "application/xml")); System.out.println("Response code: " + response.getStatus()); response.close(); client.close(); @@ -126,14 +112,13 @@ public class EnvoyClient { wrapper.getMessage().addAll(Arrays.asList(messages)); return wrapper; } - + public Users getUsersListXml() { - Client client = ClientBuilder.newClient(); - WebTarget target = client.target(String.format("%s:%s/envoy-server/rest/user", - serverProps.getProperty("server"), - serverProps.getProperty("port"))); - Response response = target.request("application/xml").get(); - Users users = response.readEntity(Users.class); + javax.ws.rs.client.Client client = ClientBuilder.newClient(); + WebTarget target = client + .target(String.format("%s:%d/envoy-server/rest/user", config.getServer(), config.getPort())); + Response response = target.request("application/xml").get(); + Users users = response.readEntity(Users.class); System.out.println("Response code: " + response.getStatus()); response.close(); client.close(); diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java new file mode 100644 index 0000000..8ee95bd --- /dev/null +++ b/src/main/java/envoy/client/Config.java @@ -0,0 +1,46 @@ +package envoy.client; + +import java.util.Properties; + +/** + * Project: envoy-client
+ * File: Config.java
+ * Created: 12 Oct 2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy 0.1 + */ +public class Config { + + private String server; + private int port; + + public void load(Properties properties) { + if (properties.containsKey("server")) server = properties.getProperty("server"); + if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); + } + + public void load(String[] args) { + for (int i = 0; i < args.length; i++) + switch (args[i]) { + case "--server": + case "-s": + server = args[++i]; + break; + case "--port": + case "-p": + port = Integer.parseInt(args[++i]); + break; + } + } + + public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0; } + + public String getServer() { return server; } + + public void setServer(String server) { this.server = server; } + + public int getPort() { return port; } + + public void setPort(int port) { this.port = port; } +} diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 178c738..6e4891d 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -8,6 +8,7 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.io.IOException; +import java.util.Properties; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -20,12 +21,9 @@ import javax.swing.JTextArea; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; -import javax.xml.parsers.ParserConfigurationException; -import org.apache.http.client.ClientProtocolException; -import org.xml.sax.SAXException; - -import envoy.client.EnvoyClient; +import envoy.client.Client; +import envoy.client.Config; import envoy.schema.Message; import envoy.schema.User; import envoy.schema.Users; @@ -43,9 +41,10 @@ public class ChatWindow extends JFrame { private static final long serialVersionUID = 6865098428255463649L; - private long recipientID = 0; - private JPanel contentPane = new JPanel(); - private EnvoyClient envoyClient = new EnvoyClient(); + private long recipientID = 0; + private JPanel contentPane = new JPanel(); + + private static Client client; private DefaultListModel messageListModel = new DefaultListModel<>(); @@ -136,8 +135,8 @@ public class ChatWindow extends JFrame { // TODO: Acquire proper sender id if (!messageEnterTextfield.getText().isEmpty() && recipientID != 0) try { - final Message message = envoyClient.createMessage(1, recipientID, messageEnterTextfield.getText()); - envoyClient.sendMessage(message); + final Message message = client.createMessage(1, recipientID, messageEnterTextfield.getText()); + client.sendMessage(message); appendMessageToChat(message); messageEnterTextfield.setText(""); } catch (Exception e) { @@ -187,7 +186,7 @@ public class ChatWindow extends JFrame { */ private void loadUserList(JList userList) { new Thread(() -> { - Users users = envoyClient.getUsersListXml(); + Users users = client.getUsersListXml(); DefaultListModel userListModel = new DefaultListModel<>(); users.getUser().forEach(user -> userListModel.addElement(user)); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); @@ -213,8 +212,28 @@ public class ChatWindow extends JFrame { + getFirstTextContent(message) + ""); } - public static void main(String[] args) - throws ClientProtocolException, IOException, SAXException, ParserConfigurationException { + public static void main(String[] args) { + Config config = new Config(); + if (args.length > 0) { + config.load(args); + } else { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + try { + Properties configProperties = new Properties(); + configProperties.load(loader.getResourceAsStream("server.properties")); + config.load(configProperties); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if(!config.isInitialized()) { + System.err.println("Server or port are not defined. Exiting..."); + System.exit(1); + } + + client = new Client(config); + EventQueue.invokeLater(() -> { try { ChatWindow frame = new ChatWindow(); From c2c5b6e1054e4b554ab1d87a71d9434410f7fe2d Mon Sep 17 00:00:00 2001 From: leon Date: Sat, 12 Oct 2019 11:52:29 +0200 Subject: [PATCH 027/474] Added Javadoc to Config file. --- src/main/java/envoy/client/Config.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 8ee95bd..fda0f97 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -15,11 +15,25 @@ public class Config { private String server; private int port; + /** + * Defaults to the {@code server.properties} file for information. + * + * + * @param properties - The two options for internet connection server and port + * @since Envoy 0.1 + */ public void load(Properties properties) { if (properties.containsKey("server")) server = properties.getProperty("server"); if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); } + /** + * Sets the server and the port via command line properties --server/ -s and --port/ -p. + * + * @param args {@code --server} or {@code -s} followed by the specified URL + * and {@code --port} or {@code -p} followed by a 4-digit Integer + * @since Envoy 0.1 + */ public void load(String[] args) { for (int i = 0; i < args.length; i++) switch (args[i]) { From adefab34ccbfa1eb8968a641a17fef66a1b74528 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 12 Oct 2019 14:45:58 +0200 Subject: [PATCH 028/474] Added Startup class and login by username. --- src/main/java/envoy/client/Client.java | 26 +++++++- src/main/java/envoy/client/ui/ChatWindow.java | 38 ++--------- src/main/java/envoy/client/ui/Startup.java | 63 +++++++++++++++++++ 3 files changed, 93 insertions(+), 34 deletions(-) create mode 100644 src/main/java/envoy/client/ui/Startup.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index f302a39..51ee5c0 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -17,6 +17,7 @@ import envoy.schema.Message; import envoy.schema.Message.MetaData.MessageState; import envoy.schema.Messages; import envoy.schema.ObjectFactory; +import envoy.schema.User; import envoy.schema.Users; /** @@ -26,6 +27,7 @@ import envoy.schema.Users; * * @author Kai S. K. Engelbart * @author Maximilian Käfer + * @author Leon Hofmeister * @since Envoy 0.1 */ @@ -34,14 +36,17 @@ public class Client { private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; private Config config; + private User user; - public Client(Config config) { + public Client(Config config, String username) { this.config = config; try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException e) { e.printStackTrace(); } + user = getUser(username); + System.out.printf("Mein Name ist %s und ich habe die ID %d%n", user.getName(), user.getID()); } /** @@ -124,4 +129,23 @@ public class Client { client.close(); return users; } + + /** + * Returns the user by name. + * + * @param name - the name of the user + * @return an user object + * @since Envoy 0.1 + */ + private User getUser(String name) { + javax.ws.rs.client.Client client = ClientBuilder.newClient(); + WebTarget target = client + .target(String.format("%s:%d/envoy-server/rest/user/sender?name=" + name, config.getServer(), config.getPort())); + Response response = target.request("application/xml").get(); + Users users = response.readEntity(Users.class); + System.out.println("Response code: " + response.getStatus()); + response.close(); + client.close(); + return users.getUser().get(0); + } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 6e4891d..8f71776 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -35,6 +35,7 @@ import envoy.schema.Users; * * @author Kai S. K. Engelbart * @author Maximilian Käfer + * @author Leon Hofmeister * @since Envoy 0.1 */ public class ChatWindow extends JFrame { @@ -44,11 +45,13 @@ public class ChatWindow extends JFrame { private long recipientID = 0; private JPanel contentPane = new JPanel(); - private static Client client; + private Client client; private DefaultListModel messageListModel = new DefaultListModel<>(); - public ChatWindow() { + public ChatWindow(Client client) { + this.client = client; + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); setTitle("Envoy"); @@ -212,35 +215,4 @@ public class ChatWindow extends JFrame { + getFirstTextContent(message) + ""); } - public static void main(String[] args) { - Config config = new Config(); - if (args.length > 0) { - config.load(args); - } else { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - try { - Properties configProperties = new Properties(); - configProperties.load(loader.getResourceAsStream("server.properties")); - config.load(configProperties); - } catch (IOException e) { - e.printStackTrace(); - } - } - - if(!config.isInitialized()) { - System.err.println("Server or port are not defined. Exiting..."); - System.exit(1); - } - - client = new Client(config); - - EventQueue.invokeLater(() -> { - try { - ChatWindow frame = new ChatWindow(); - frame.setVisible(true); - } catch (Exception e) { - e.printStackTrace(); - } - }); - } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java new file mode 100644 index 0000000..d2848a9 --- /dev/null +++ b/src/main/java/envoy/client/ui/Startup.java @@ -0,0 +1,63 @@ +package envoy.client.ui; + +import java.awt.EventQueue; +import java.io.IOException; +import java.util.Properties; + +import javax.swing.JOptionPane; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; + +import envoy.client.Client; +import envoy.client.Config; + +/** + * Starts Envoy and sets a user. + * + * Project: envoy-client
+ * File: Startup.java
+ * Created: 12 Oct 2019
+ * + * @author Leon Hofmeister + * @author Maximilian Käfer + * @since Envoy 0.1 + */ +public class Startup { + + private static String userName; + + public static void main(String[] args) { + Config config = new Config(); + if (args.length > 0) { + config.load(args); + } else { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + try { + Properties configProperties = new Properties(); + configProperties.load(loader.getResourceAsStream("server.properties")); + config.load(configProperties); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if(!config.isInitialized()) { + System.err.println("Server or port are not defined. Exiting..."); + System.exit(1); + } + + userName = JOptionPane.showInputDialog("Please enter your username"); + + Client client = new Client(config, userName); + + EventQueue.invokeLater(() -> { + try { + ChatWindow frame = new ChatWindow(client); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } +} From 00f70f19fbefd142391dba820607d0af9f5e24a8 Mon Sep 17 00:00:00 2001 From: Maxi Date: Sat, 12 Oct 2019 17:35:58 +0200 Subject: [PATCH 029/474] Added the setting of the senderID in the xml. --- src/main/java/envoy/client/Client.java | 10 ++++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 51ee5c0..c87d616 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -148,4 +148,14 @@ public class Client { client.close(); return users.getUser().get(0); } + + /** + * Returns the user ID. + * @return userID + * @since Envoy 0.1 + */ + public long getSenderID() { + return user.getID(); + + } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 8f71776..0d20f74 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -138,7 +138,7 @@ public class ChatWindow extends JFrame { // TODO: Acquire proper sender id if (!messageEnterTextfield.getText().isEmpty() && recipientID != 0) try { - final Message message = client.createMessage(1, recipientID, messageEnterTextfield.getText()); + final Message message = client.createMessage(client.getSenderID(), recipientID, messageEnterTextfield.getText()); client.sendMessage(message); appendMessageToChat(message); messageEnterTextfield.setText(""); From ff8beae4f6c06883e42229c89ac624767104fea6 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 13 Oct 2019 17:25:20 +0200 Subject: [PATCH 030/474] Fixed formatting and Javadoc Closes #5 --- src/main/java/envoy/client/Client.java | 32 ++++++++----------- src/main/java/envoy/client/ui/ChatWindow.java | 10 ++---- src/main/java/envoy/client/ui/Startup.java | 22 ++++++------- 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index c87d616..53a7865 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -36,7 +36,7 @@ public class Client { private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; private Config config; - private User user; + private User user; public Client(Config config, String username) { this.config = config; @@ -54,9 +54,9 @@ public class Client { * Because sending a request is a blocking operation, it is executed * asynchronously. * - * @param sender Name of the sender - * @param recipient Name of the recipient - * @param textContent Content (text) of the message + * @param sender name of the sender + * @param recipient name of the recipient + * @param textContent content (text) of the message */ public void sendMessage(Message message) { new Thread(() -> { @@ -92,7 +92,7 @@ public class Client { * @param senderID The ID of the sender * @param recipientID The ID of the recipient * @param textContent The content (text) of the message - * @return Prepared {@link Message} object + * @return prepared {@link Message} object */ public Message createMessage(long senderID, long recipientID, String textContent) { Message.MetaData metaData = objectFactory.createMessageMetaData(); @@ -129,18 +129,18 @@ public class Client { client.close(); return users; } - + /** - * Returns the user by name. + * Returns a {@link User} with a specific name by name. * - * @param name - the name of the user - * @return an user object + * @param name - the name of the {@link User} + * @return a {@link User} with the specified name * @since Envoy 0.1 */ private User getUser(String name) { javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client - .target(String.format("%s:%d/envoy-server/rest/user/sender?name=" + name, config.getServer(), config.getPort())); + WebTarget target = client.target(String + .format("%s:%d/envoy-server/rest/user/sender?name=" + name, config.getServer(), config.getPort())); Response response = target.request("application/xml").get(); Users users = response.readEntity(Users.class); System.out.println("Response code: " + response.getStatus()); @@ -148,14 +148,10 @@ public class Client { client.close(); return users.getUser().get(0); } - + /** - * Returns the user ID. - * @return userID + * @return the user id of this client * @since Envoy 0.1 */ - public long getSenderID() { - return user.getID(); - - } + public long getSenderID() { return user.getID(); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 0d20f74..0e9bc40 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -2,13 +2,10 @@ package envoy.client.ui; import java.awt.Color; import java.awt.ComponentOrientation; -import java.awt.EventQueue; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; -import java.io.IOException; -import java.util.Properties; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -23,7 +20,6 @@ import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import envoy.client.Client; -import envoy.client.Config; import envoy.schema.Message; import envoy.schema.User; import envoy.schema.Users; @@ -51,7 +47,7 @@ public class ChatWindow extends JFrame { public ChatWindow(Client client) { this.client = client; - + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); setTitle("Envoy"); @@ -138,7 +134,8 @@ public class ChatWindow extends JFrame { // TODO: Acquire proper sender id if (!messageEnterTextfield.getText().isEmpty() && recipientID != 0) try { - final Message message = client.createMessage(client.getSenderID(), recipientID, messageEnterTextfield.getText()); + final Message message = client + .createMessage(client.getSenderID(), recipientID, messageEnterTextfield.getText()); client.sendMessage(message); appendMessageToChat(message); messageEnterTextfield.setText(""); @@ -214,5 +211,4 @@ public class ChatWindow extends JFrame { + message.getMetaData().getSender() + " " + "
" + "

" + getFirstTextContent(message) + ""); } - } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index d2848a9..b525861 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -5,15 +5,12 @@ import java.io.IOException; import java.util.Properties; import javax.swing.JOptionPane; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Response; import envoy.client.Client; import envoy.client.Config; /** - * Starts Envoy and sets a user. + * Starts the Envoy client and prompts the user to enter their name. * * Project: envoy-client
* File: Startup.java
@@ -24,9 +21,7 @@ import envoy.client.Config; * @since Envoy 0.1 */ public class Startup { - - private static String userName; - + public static void main(String[] args) { Config config = new Config(); if (args.length > 0) { @@ -42,15 +37,18 @@ public class Startup { } } - if(!config.isInitialized()) { + if (!config.isInitialized()) { System.err.println("Server or port are not defined. Exiting..."); System.exit(1); } - userName = JOptionPane.showInputDialog("Please enter your username"); - + String userName = JOptionPane.showInputDialog("Please enter your username"); + if (userName == null || userName.isEmpty()) { + System.err.println("User name is not set or empty. Exiting..."); + System.exit(1); + } Client client = new Client(config, userName); - + EventQueue.invokeLater(() -> { try { ChatWindow frame = new ChatWindow(client); @@ -60,4 +58,4 @@ public class Startup { } }); } -} +} \ No newline at end of file From ce3d69c6b092c901db666e11ccda4357ce8eeb05 Mon Sep 17 00:00:00 2001 From: Maxi Date: Sat, 19 Oct 2019 09:59:45 +0200 Subject: [PATCH 031/474] Implemented multiple chat system * Local saving of these and displaying the partner name * Added display of timestamp in chat. Closes #9 --- src/main/java/envoy/client/Chat.java | 58 ++++++++++++ src/main/java/envoy/client/Client.java | 2 + src/main/java/envoy/client/ui/ChatWindow.java | 89 +++++++++++++++++-- 3 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 src/main/java/envoy/client/Chat.java diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java new file mode 100644 index 0000000..2d8c519 --- /dev/null +++ b/src/main/java/envoy/client/Chat.java @@ -0,0 +1,58 @@ +package envoy.client; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.DefaultListModel; + +import envoy.schema.Message; + +public class Chat { + + public long chatPartnerID; + public List messageList; + DefaultListModel chatModel; + public Chat() { + chatPartnerID = 0; + chatModel = new DefaultListModel(); + messageList = new ArrayList(); + } + + public void setUserID(long givenUserID) { + chatPartnerID = givenUserID; + } + + public long getUserID() { + return chatPartnerID; + } + + public int getSize() { + return chatModel.getSize(); + } + + public void addMessage(String message) { + chatModel.addElement(message); + } + + public String getMessageAt(int index) { + return (String) chatModel.getElementAt(index); + } + + @SuppressWarnings("unchecked") + public DefaultListModel getModel() { + return chatModel; + } + + public int getListSize() { + return messageList.size(); + } + + public void addMessageElement(Message message) { + messageList.add(message); + } + + public Message getMessageElement(int index) { + return messageList.get(index); + } + +} diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 53a7865..149db18 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -154,4 +154,6 @@ public class Client { * @since Envoy 0.1 */ public long getSenderID() { return user.getID(); } + + public User getClientUser() { return user;} } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 0e9bc40..94ec2d4 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -6,6 +6,8 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.util.ArrayList; +import java.util.List; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -15,10 +17,12 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; +import javax.swing.JTextPane; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; +import envoy.client.Chat; import envoy.client.Client; import envoy.schema.Message; import envoy.schema.User; @@ -43,11 +47,21 @@ public class ChatWindow extends JFrame { private Client client; - private DefaultListModel messageListModel = new DefaultListModel<>(); + private DefaultListModel messageListModel = new DefaultListModel<>(); + private List partnerChatList = new ArrayList(); + @SuppressWarnings("null") public ChatWindow(Client client) { this.client = client; + Users chatUsers = client.getUsersListXml(); + + for (int i = 0; i < chatUsers.getUser().size(); i++) { + Chat userChat = new Chat(); + userChat.setUserID(chatUsers.getUser().get(i).getID()); + partnerChatList.add(userChat); + } + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); setTitle("Envoy"); @@ -55,7 +69,7 @@ public class ChatWindow extends JFrame { contentPane.setBackground(new Color(0, 0, 0)); contentPane.setForeground(Color.white); - contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + contentPane.setBorder(new EmptyBorder(0, 5, 0, 0)); setContentPane(contentPane); GridBagLayout gbl_contentPane = new GridBagLayout(); gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; @@ -90,7 +104,7 @@ public class ChatWindow extends JFrame { gbc_scrollPane.gridx = 1; gbc_scrollPane.gridy = 1; - gbc_scrollPane.insets = new Insets(10, 10, 10, 10); + gbc_scrollPane.insets = new Insets(0, 10, 10, 10); contentPane.add(scrollPane, gbc_scrollPane); @@ -137,8 +151,18 @@ public class ChatWindow extends JFrame { final Message message = client .createMessage(client.getSenderID(), recipientID, messageEnterTextfield.getText()); client.sendMessage(message); - appendMessageToChat(message); + Chat partnerChat = null; + for (int i = 0; i < partnerChatList.size(); i++) { + if (recipientID == partnerChatList.get(i).getUserID()) { + partnerChat = partnerChatList.get(i); + // System.out.println("partnerChatID: " + partnerChatList.get(i).getUserID()); + + } + } + appendMessageToChat(message, partnerChat); messageEnterTextfield.setText(""); + elementList.setModel(partnerChat.getModel()); + contentPane.revalidate(); } catch (Exception e) { JOptionPane.showMessageDialog(this, "An exception occured while sending a message. See the log for more details.", @@ -148,6 +172,22 @@ public class ChatWindow extends JFrame { } }); + // Partner name display + JTextPane textPane = new JTextPane(); + textPane.setBackground(new Color(0, 0, 0)); + textPane.setForeground(new Color(255, 255, 255)); + + textPane.setFont(new Font("Arial", Font.PLAIN, 20)); + + GridBagConstraints gbc_partnerName = new GridBagConstraints(); + gbc_partnerName.fill = GridBagConstraints.HORIZONTAL; + gbc_partnerName.gridwidth = 2; + gbc_partnerName.gridx = 1; + gbc_partnerName.gridy = 0; + + gbc_partnerName.insets = new Insets(0, 10, 0, 10); + contentPane.add(textPane, gbc_partnerName); + JList userList = new JList<>(); userList.setCellRenderer(new UserListRenderer()); userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); @@ -156,6 +196,20 @@ public class ChatWindow extends JFrame { @SuppressWarnings("unchecked") JList selectedUserList = (JList) listSelectionEvent.getSource(); recipientID = selectedUserList.getModel().getElementAt(selectedUserList.getSelectedIndex()).getID(); + Chat selectedChat = null; + + for (int i = 0; i < partnerChatList.size(); i++) { + if (selectedUserList.getSelectedIndex() == partnerChatList.get(i).getUserID() - 1) { + selectedChat = partnerChatList.get(i); + + } + } + User partner = getPartner(); + System.out.println(partner.getName()); + textPane.setText(partner.getName()); + elementList.setModel(selectedChat.getModel()); + contentPane.revalidate(); + } }); @@ -167,10 +221,11 @@ public class ChatWindow extends JFrame { userList.setBorder(new EmptyBorder(5, 5, 5, 5)); GridBagConstraints gbc_userList = new GridBagConstraints(); + gbc_userList.fill = GridBagConstraints.VERTICAL; gbc_userList.gridx = 0; gbc_userList.gridy = 1; gbc_userList.anchor = GridBagConstraints.PAGE_START; - gbc_userList.insets = new Insets(10, 0, 10, 0); + gbc_userList.insets = new Insets(0, 0, 10, 0); contentPane.add(userList, gbc_userList); contentPane.revalidate(); @@ -206,9 +261,25 @@ public class ChatWindow extends JFrame { * * @param message The message to append */ - private void appendMessageToChat(Message message) { - messageListModel.addElement("" + "

" - + message.getMetaData().getSender() + " " + "
" + "

" - + getFirstTextContent(message) + ""); + private void appendMessageToChat(Message message, Chat partnerChat) { + partnerChat.addMessage("" + + "

" + + client.getClientUser().getName() + " " + + (message.getMetaData().getDate().getHour() + 2) + ":" //Dont know why this parameter 2 hours back. + + message.getMetaData().getDate().getMinute() + ":" + + message.getMetaData().getDate().getSecond() + //Dont know + + " " + "
" + "

" + getFirstTextContent(message) + + ""); + partnerChat.addMessageElement(message); + } + + public User getPartner() { + Users users = client.getUsersListXml(); + User partner = null; + for (int i = 0; i < users.getUser().size(); i++) { + if (users.getUser().get(i).getID() == recipientID) { partner = users.getUser().get(i); } + } + return partner; } } \ No newline at end of file From 4022e227cac6e1cc69b2f0559e5ea31b820fb7bb Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 19 Oct 2019 10:14:46 +0200 Subject: [PATCH 032/474] Formatted Chat file Formatted Getters and Setters --- src/main/java/envoy/client/Chat.java | 36 +++++++--------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index 2d8c519..a38c3bb 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -18,41 +18,23 @@ public class Chat { messageList = new ArrayList(); } - public void setUserID(long givenUserID) { - chatPartnerID = givenUserID; - } + public void setUserID(long givenUserID) { chatPartnerID = givenUserID;} - public long getUserID() { - return chatPartnerID; - } + public long getUserID() { return chatPartnerID;} - public int getSize() { - return chatModel.getSize(); - } + public int getSize() { return chatModel.getSize();} - public void addMessage(String message) { - chatModel.addElement(message); - } + public void addMessage(String message) { chatModel.addElement(message);} - public String getMessageAt(int index) { - return (String) chatModel.getElementAt(index); - } + public String getMessageAt(int index) { return (String) chatModel.getElementAt(index);} @SuppressWarnings("unchecked") - public DefaultListModel getModel() { - return chatModel; - } + public DefaultListModel getModel() { return chatModel;} - public int getListSize() { - return messageList.size(); - } + public int getListSize() { return messageList.size();} - public void addMessageElement(Message message) { - messageList.add(message); - } + public void addMessageElement(Message message) { messageList.add(message);} - public Message getMessageElement(int index) { - return messageList.get(index); - } + public Message getMessageElement(int index) { return messageList.get(index);} } From 8751bd8781dbe3dd8974312c4aca0e2c3ce52b2b Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 19 Oct 2019 12:10:52 +0200 Subject: [PATCH 033/474] Changed message list to use JLabels as elements * Using JLabel as message list element * Managing sender and recipient in Client * Reduced amount of ReST requests --- src/main/java/envoy/client/Chat.java | 44 ++---- src/main/java/envoy/client/Client.java | 25 ++-- src/main/java/envoy/client/ui/ChatWindow.java | 136 +++++++----------- .../envoy/client/ui/MessageListRenderer.java | 42 ++++++ 4 files changed, 116 insertions(+), 131 deletions(-) create mode 100644 src/main/java/envoy/client/ui/MessageListRenderer.java diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index a38c3bb..3f48c7c 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -1,40 +1,20 @@ package envoy.client; -import java.util.ArrayList; -import java.util.List; - import javax.swing.DefaultListModel; import envoy.schema.Message; +import envoy.schema.User; public class Chat { - public long chatPartnerID; - public List messageList; - DefaultListModel chatModel; - public Chat() { - chatPartnerID = 0; - chatModel = new DefaultListModel(); - messageList = new ArrayList(); - } - - public void setUserID(long givenUserID) { chatPartnerID = givenUserID;} - - public long getUserID() { return chatPartnerID;} - - public int getSize() { return chatModel.getSize();} - - public void addMessage(String message) { chatModel.addElement(message);} - - public String getMessageAt(int index) { return (String) chatModel.getElementAt(index);} - - @SuppressWarnings("unchecked") - public DefaultListModel getModel() { return chatModel;} - - public int getListSize() { return messageList.size();} - - public void addMessageElement(Message message) { messageList.add(message);} - - public Message getMessageElement(int index) { return messageList.get(index);} - -} + private User recipient; + private DefaultListModel model = new DefaultListModel<>(); + + public Chat(User recipient) { this.recipient = recipient; } + + public User getRecipient() { return recipient; } + + public void appendMessage(Message message) { model.addElement(message); } + + public DefaultListModel getModel() { return model; } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 149db18..8468c56 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -36,7 +36,7 @@ public class Client { private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; private Config config; - private User user; + private User sender, recipient; public Client(Config config, String username) { this.config = config; @@ -45,8 +45,7 @@ public class Client { } catch (DatatypeConfigurationException e) { e.printStackTrace(); } - user = getUser(username); - System.out.printf("Mein Name ist %s und ich habe die ID %d%n", user.getName(), user.getID()); + sender = getUser(username); } /** @@ -89,15 +88,13 @@ public class Client { /** * Creates a {@link Message} object serializable to XML. * - * @param senderID The ID of the sender - * @param recipientID The ID of the recipient * @param textContent The content (text) of the message * @return prepared {@link Message} object */ - public Message createMessage(long senderID, long recipientID, String textContent) { + public Message createMessage(String textContent) { Message.MetaData metaData = objectFactory.createMessageMetaData(); - metaData.setSender(senderID); - metaData.setRecipient(recipientID); + metaData.setSender(sender.getID()); + metaData.setRecipient(recipient.getID()); metaData.setState(MessageState.WAITING); metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); @@ -150,10 +147,14 @@ public class Client { } /** - * @return the user id of this client + * @return the sender object that represents this client * @since Envoy 0.1 */ - public long getSenderID() { return user.getID(); } - - public User getClientUser() { return user;} + public User getSender() { return sender; } + + public User getRecipient() { return recipient; } + + public void setRecipient(User recipient) { this.recipient = recipient; } + + public boolean hasRecipient() { return recipient != null; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 94ec2d4..9b07a6c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -42,25 +42,21 @@ public class ChatWindow extends JFrame { private static final long serialVersionUID = 6865098428255463649L; - private long recipientID = 0; - private JPanel contentPane = new JPanel(); + private JPanel contentPane = new JPanel(); private Client client; - private DefaultListModel messageListModel = new DefaultListModel<>(); + private DefaultListModel messageListModel = new DefaultListModel<>(); private List partnerChatList = new ArrayList(); + private Chat currentChat; - @SuppressWarnings("null") public ChatWindow(Client client) { this.client = client; + // Initialize chat list and current chat Users chatUsers = client.getUsersListXml(); - - for (int i = 0; i < chatUsers.getUser().size(); i++) { - Chat userChat = new Chat(); - userChat.setUserID(chatUsers.getUser().get(i).getID()); - partnerChatList.add(userChat); - } + chatUsers.getUser().forEach(user -> partnerChatList.add(new Chat(user))); + if (partnerChatList.size() > 0) currentChat = partnerChatList.get(0); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); @@ -78,24 +74,25 @@ public class ChatWindow extends JFrame { gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; contentPane.setLayout(gbl_contentPane); - JList elementList = new JList<>(); - elementList.setFocusTraversalKeysEnabled(false); + JList messageList = new JList<>(); + messageList.setCellRenderer(new MessageListRenderer()); - elementList.setSelectionForeground(new Color(255, 255, 255)); - elementList.setSelectionBackground(new Color(102, 0, 153)); - elementList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); - elementList.setForeground(new Color(255, 255, 255)); - elementList.setBackground(new Color(51, 51, 51)); + messageList.setFocusTraversalKeysEnabled(false); + messageList.setSelectionForeground(new Color(255, 255, 255)); + messageList.setSelectionBackground(new Color(102, 0, 153)); + messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + messageList.setForeground(new Color(255, 255, 255)); + messageList.setBackground(new Color(51, 51, 51)); - elementList.setModel(messageListModel); - elementList.setFont(new Font("Arial", Font.PLAIN, 17)); - elementList.setFixedCellHeight(60); - elementList.setBorder(new EmptyBorder(5, 5, 5, 5)); + messageList.setModel(messageListModel); + messageList.setFont(new Font("Arial", Font.PLAIN, 17)); + messageList.setFixedCellHeight(60); + messageList.setBorder(new EmptyBorder(5, 5, 5, 5)); JScrollPane scrollPane = new JScrollPane(); scrollPane.setForeground(new Color(0, 0, 0)); scrollPane.setBackground(new Color(51, 51, 51)); - scrollPane.setViewportView(elementList); + scrollPane.setViewportView(messageList); scrollPane.setBorder(null); GridBagConstraints gbc_scrollPane = new GridBagConstraints(); @@ -141,27 +138,27 @@ public class ChatWindow extends JFrame { gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); - contentPane.add(postButton, gbc_moveSelectionPostButton); - postButton.addActionListener((evt) -> { - if (recipientID == 0) System.out.println("Please select recipient"); + if (!client.hasRecipient()) { + JOptionPane.showMessageDialog(this, + "Please select a recipient!", + "Cannot send message", + JOptionPane.INFORMATION_MESSAGE); + return; + } - // TODO: Acquire proper sender id - if (!messageEnterTextfield.getText().isEmpty() && recipientID != 0) try { - final Message message = client - .createMessage(client.getSenderID(), recipientID, messageEnterTextfield.getText()); + if (!messageEnterTextfield.getText().isEmpty()) try { + + // Create and send message object + final Message message = client.createMessage(messageEnterTextfield.getText()); client.sendMessage(message); - Chat partnerChat = null; - for (int i = 0; i < partnerChatList.size(); i++) { - if (recipientID == partnerChatList.get(i).getUserID()) { - partnerChat = partnerChatList.get(i); - // System.out.println("partnerChatID: " + partnerChatList.get(i).getUserID()); - } - } - appendMessageToChat(message, partnerChat); + // Append message object to chat + currentChat.appendMessage(message); + messageList.setModel(currentChat.getModel()); + + // Clear text field messageEnterTextfield.setText(""); - elementList.setModel(partnerChat.getModel()); contentPane.revalidate(); } catch (Exception e) { JOptionPane.showMessageDialog(this, @@ -172,6 +169,8 @@ public class ChatWindow extends JFrame { } }); + contentPane.add(postButton, gbc_moveSelectionPostButton); + // Partner name display JTextPane textPane = new JTextPane(); textPane.setBackground(new Color(0, 0, 0)); @@ -194,22 +193,20 @@ public class ChatWindow extends JFrame { userList.addListSelectionListener((listSelectionEvent) -> { if (!listSelectionEvent.getValueIsAdjusting()) { @SuppressWarnings("unchecked") - JList selectedUserList = (JList) listSelectionEvent.getSource(); - recipientID = selectedUserList.getModel().getElementAt(selectedUserList.getSelectedIndex()).getID(); - Chat selectedChat = null; + final JList selectedUserList = (JList) listSelectionEvent.getSource(); + final User user = selectedUserList.getSelectedValue(); + client.setRecipient(user); - for (int i = 0; i < partnerChatList.size(); i++) { - if (selectedUserList.getSelectedIndex() == partnerChatList.get(i).getUserID() - 1) { - selectedChat = partnerChatList.get(i); + currentChat = partnerChatList.stream() + .filter(chat -> chat.getRecipient().getID() == user.getID()) + .findFirst() + .get(); - } - } - User partner = getPartner(); - System.out.println(partner.getName()); - textPane.setText(partner.getName()); - elementList.setModel(selectedChat.getModel()); + client.setRecipient(user); + + textPane.setText(currentChat.getRecipient().getName()); + messageList.setModel(currentChat.getModel()); contentPane.revalidate(); - } }); @@ -221,7 +218,7 @@ public class ChatWindow extends JFrame { userList.setBorder(new EmptyBorder(5, 5, 5, 5)); GridBagConstraints gbc_userList = new GridBagConstraints(); - gbc_userList.fill = GridBagConstraints.VERTICAL; + gbc_userList.fill = GridBagConstraints.VERTICAL; gbc_userList.gridx = 0; gbc_userList.gridy = 1; gbc_userList.anchor = GridBagConstraints.PAGE_START; @@ -247,39 +244,4 @@ public class ChatWindow extends JFrame { SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); }).start(); } - - /** - * Extracts the first text content from a message. - * - * @param message The message from which to return the text content - * @return The first content of type 'text' - */ - private String getFirstTextContent(Message message) { return message.getContent().get(0).getText(); } - - /** - * Appends a message with sender and message content to the message list. - * - * @param message The message to append - */ - private void appendMessageToChat(Message message, Chat partnerChat) { - partnerChat.addMessage("" - + "

" - + client.getClientUser().getName() + " " - + (message.getMetaData().getDate().getHour() + 2) + ":" //Dont know why this parameter 2 hours back. - + message.getMetaData().getDate().getMinute() + ":" - + message.getMetaData().getDate().getSecond() - //Dont know - + " " + "
" + "

" + getFirstTextContent(message) - + ""); - partnerChat.addMessageElement(message); - } - - public User getPartner() { - Users users = client.getUsersListXml(); - User partner = null; - for (int i = 0; i < users.getUser().size(); i++) { - if (users.getUser().get(i).getID() == recipientID) { partner = users.getUser().get(i); } - } - return partner; - } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java new file mode 100644 index 0000000..09c3c83 --- /dev/null +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -0,0 +1,42 @@ +package envoy.client.ui; + +import java.awt.Component; + +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +import envoy.schema.Message; + +/** + * Project: envoy-client
+ * File: UserListRenderer.java
+ * Created: 19 Oct 2019
+ * + * @author Kai S. K. Engelbart + */ +public class MessageListRenderer extends JLabel implements ListCellRenderer { + + private static final long serialVersionUID = 5164417379767181198L; + + @Override + public Component getListCellRendererComponent(JList list, Message value, int index, + boolean isSelected, + boolean cellHasFocus) { + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + // Enable background rendering + setOpaque(true); + + setText(value.getContent().get(0).getText()); + setFont(list.getFont()); + + return this; + } +} From 0ed71e63a394e6ac7dd0f6339794cc18766e24f1 Mon Sep 17 00:00:00 2001 From: Maxi Date: Sat, 19 Oct 2019 15:09:32 +0200 Subject: [PATCH 034/474] Requesting unread messages an assigning them to the right chat element. --- src/main/java/envoy/client/Client.java | 14 +++++++++++++- src/main/java/envoy/client/ui/ChatWindow.java | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 8468c56..ed8ebb1 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -137,7 +137,7 @@ public class Client { private User getUser(String name) { javax.ws.rs.client.Client client = ClientBuilder.newClient(); WebTarget target = client.target(String - .format("%s:%d/envoy-server/rest/user/sender?name=" + name, config.getServer(), config.getPort())); + .format("%s:%d/envoy-server/rest/user/sender?name=%s", config.getServer(), config.getPort(), name)); Response response = target.request("application/xml").get(); Users users = response.readEntity(Users.class); System.out.println("Response code: " + response.getStatus()); @@ -146,6 +146,18 @@ public class Client { return users.getUser().get(0); } + public Messages getUnreadMessages(long userId) { + javax.ws.rs.client.Client client = ClientBuilder.newClient(); + WebTarget target = client.target(String + .format("%s:%d/envoy-server/rest/message/receive?userId=%d", config.getServer(), config.getPort(), userId)); + Response response = target.request("application/xml").get(); + Messages unreadMessages = response.readEntity(Messages.class); + System.out.println("Response code: " + response.getStatus()); + response.close(); + client.close(); + return unreadMessages; + } + /** * @return the sender object that represents this client * @since Envoy 0.1 diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 9b07a6c..8f11ec2 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -20,11 +20,13 @@ import javax.swing.JTextArea; import javax.swing.JTextPane; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; +import javax.swing.Timer; import javax.swing.border.EmptyBorder; import envoy.client.Chat; import envoy.client.Client; import envoy.schema.Message; +import envoy.schema.Messages; import envoy.schema.User; import envoy.schema.Users; @@ -228,6 +230,19 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); loadUserList(userList); + + new Timer(5000, (evt) -> { + Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); + System.out.println(unreadMessages.getMessage().get(0)); + for (int i = 0; i < unreadMessages.getMessage().size(); i++) { + for (int j = 0; j < partnerChatList.size(); j++) { + if(partnerChatList.get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) { + partnerChatList.get(j).appendMessage(unreadMessages.getMessage().get(i)); + } + } + } + }).start(); + contentPane.revalidate(); } /** From 3916c14ab66632996d9662d5f5eb59a951fd8871 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 23 Oct 2019 05:49:15 +0200 Subject: [PATCH 035/474] Added HTML formatting to message list elements --- .../java/envoy/client/ui/MessageListRenderer.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 09c3c83..ad965c4 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -1,6 +1,7 @@ package envoy.client.ui; import java.awt.Component; +import java.text.SimpleDateFormat; import javax.swing.JLabel; import javax.swing.JList; @@ -21,8 +22,7 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer list, Message value, int index, - boolean isSelected, - boolean cellHasFocus) { + boolean isSelected, boolean cellHasFocus) { if (isSelected) { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); @@ -31,11 +31,13 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer

%s

%s", + new SimpleDateFormat("dd.MM.yyyy hh:mm ") + .format(value.getMetaData().getDate().toGregorianCalendar().getTime()), + value.getContent().get(0).getText())); return this; } From 1ded9df82ba68c48c109bd1d661c61432d32a10d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 23 Oct 2019 17:17:15 +0200 Subject: [PATCH 036/474] Fixed NullPointerException on empty date --- src/main/java/envoy/client/ui/ChatWindow.java | 12 +++++------- .../java/envoy/client/ui/MessageListRenderer.java | 11 +++++++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 8f11ec2..cce9e73 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -233,14 +233,12 @@ public class ChatWindow extends JFrame { new Timer(5000, (evt) -> { Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); - System.out.println(unreadMessages.getMessage().get(0)); - for (int i = 0; i < unreadMessages.getMessage().size(); i++) { - for (int j = 0; j < partnerChatList.size(); j++) { - if(partnerChatList.get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) { + for (int i = 0; i < unreadMessages.getMessage().size(); i++) + for (int j = 0; j < partnerChatList.size(); j++) + if (partnerChatList.get(j) + .getRecipient() + .getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) partnerChatList.get(j).appendMessage(unreadMessages.getMessage().get(i)); - } - } - } }).start(); contentPane.revalidate(); } diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index ad965c4..a61ae5f 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -33,12 +33,15 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer

%s

%s", - new SimpleDateFormat("dd.MM.yyyy hh:mm ") - .format(value.getMetaData().getDate().toGregorianCalendar().getTime()), - value.getContent().get(0).getText())); - + date, + text)); return this; } } From 09b995ea0fa463188f09999482fa3ce75f870b35 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 26 Oct 2019 17:49:45 +0200 Subject: [PATCH 037/474] Reduced the number of user list requests to one Fixes #16 --- src/main/java/envoy/client/ui/ChatWindow.java | 59 +++++++++---------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index cce9e73..dd7ff5e 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -48,18 +48,13 @@ public class ChatWindow extends JFrame { private Client client; - private DefaultListModel messageListModel = new DefaultListModel<>(); - private List partnerChatList = new ArrayList(); - private Chat currentChat; + private JList userList = new JList<>(); + private List partnerChatList = new ArrayList(); + private Chat currentChat; public ChatWindow(Client client) { this.client = client; - // Initialize chat list and current chat - Users chatUsers = client.getUsersListXml(); - chatUsers.getUser().forEach(user -> partnerChatList.add(new Chat(user))); - if (partnerChatList.size() > 0) currentChat = partnerChatList.get(0); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); setTitle("Envoy"); @@ -86,6 +81,7 @@ public class ChatWindow extends JFrame { messageList.setForeground(new Color(255, 255, 255)); messageList.setBackground(new Color(51, 51, 51)); + DefaultListModel messageListModel = new DefaultListModel<>(); messageList.setModel(messageListModel); messageList.setFont(new Font("Arial", Font.PLAIN, 17)); messageList.setFixedCellHeight(60); @@ -142,10 +138,7 @@ public class ChatWindow extends JFrame { postButton.addActionListener((evt) -> { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, - "Please select a recipient!", - "Cannot send message", - JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); return; } @@ -189,7 +182,6 @@ public class ChatWindow extends JFrame { gbc_partnerName.insets = new Insets(0, 10, 0, 10); contentPane.add(textPane, gbc_partnerName); - JList userList = new JList<>(); userList.setCellRenderer(new UserListRenderer()); userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); userList.addListSelectionListener((listSelectionEvent) -> { @@ -199,10 +191,7 @@ public class ChatWindow extends JFrame { final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = partnerChatList.stream() - .filter(chat -> chat.getRecipient().getID() == user.getID()) - .findFirst() - .get(); + currentChat = partnerChatList.stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); client.setRecipient(user); @@ -229,32 +218,38 @@ public class ChatWindow extends JFrame { contentPane.add(userList, gbc_userList); contentPane.revalidate(); - loadUserList(userList); - - new Timer(5000, (evt) -> { - Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); - for (int i = 0; i < unreadMessages.getMessage().size(); i++) - for (int j = 0; j < partnerChatList.size(); j++) - if (partnerChatList.get(j) - .getRecipient() - .getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) - partnerChatList.get(j).appendMessage(unreadMessages.getMessage().get(i)); - }).start(); + loadUsersAndChats(); + startReceiverThread(5000); + contentPane.revalidate(); } /** * Initializes the elements of the user list by downloading them from the * server. - * - * @param userList The {@link JList} to put the elements in */ - private void loadUserList(JList userList) { + private void loadUsersAndChats() { new Thread(() -> { Users users = client.getUsersListXml(); DefaultListModel userListModel = new DefaultListModel<>(); - users.getUser().forEach(user -> userListModel.addElement(user)); + users.getUser().forEach(user -> { userListModel.addElement(user); partnerChatList.add(new Chat(user)); }); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); }).start(); } + + /** + * Checks for new messages and adds them to the chat list. + * + * @param timeout the amount of time that passes between two requests sent to + * the server + */ + private void startReceiverThread(int timeout) { + new Timer(timeout, (evt) -> { + Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); + for (int i = 0; i < unreadMessages.getMessage().size(); i++) + for (int j = 0; j < partnerChatList.size(); j++) + if (partnerChatList.get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) + partnerChatList.get(j).appendMessage(unreadMessages.getMessage().get(i)); + }).start(); + } } \ No newline at end of file From b1467a5cc381d5935a1dda96c858dc1c0f512d47 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 26 Oct 2019 18:31:49 +0200 Subject: [PATCH 038/474] Moved GET request implementations into a single method --- src/main/java/envoy/client/Client.java | 66 +++++++++++++------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index ed8ebb1..0ebce3c 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -60,7 +60,7 @@ public class Client { public void sendMessage(Message message) { new Thread(() -> { // Wrap single message into messages list - Messages messages = wrapMessage(message); + Messages messages = wrapMessages(message); // Print message XML to console JAXBContext jc; @@ -109,22 +109,10 @@ public class Client { return message; } - public Messages wrapMessage(Message... messages) { - Messages wrapper = objectFactory.createMessages(); - wrapper.getMessage().addAll(Arrays.asList(messages)); - return wrapper; - } + public Users getUsersListXml() { return get(String.format("%s:%d/envoy-server/rest/user", config.getServer(), config.getPort()), Users.class); } - public Users getUsersListXml() { - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client - .target(String.format("%s:%d/envoy-server/rest/user", config.getServer(), config.getPort())); - Response response = target.request("application/xml").get(); - Users users = response.readEntity(Users.class); - System.out.println("Response code: " + response.getStatus()); - response.close(); - client.close(); - return users; + public Messages getUnreadMessages(long userId) { + return get(String.format("%s:%d/envoy-server/rest/message/receive?userId=%d", config.getServer(), config.getPort(), userId), Messages.class); } /** @@ -132,35 +120,49 @@ public class Client { * * @param name - the name of the {@link User} * @return a {@link User} with the specified name - * @since Envoy 0.1 + * @since Envoy v0.1-alpha */ private User getUser(String name) { - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client.target(String - .format("%s:%d/envoy-server/rest/user/sender?name=%s", config.getServer(), config.getPort(), name)); - Response response = target.request("application/xml").get(); - Users users = response.readEntity(Users.class); - System.out.println("Response code: " + response.getStatus()); - response.close(); - client.close(); - return users.getUser().get(0); + return get(String.format("%s:%d/envoy-server/rest/user/sender?name=%s", config.getServer(), config.getPort(), name), Users.class).getUser() + .get(0); } - public Messages getUnreadMessages(long userId) { + /** + * Invokes the GET method of a web service. + * + * @param the type of the object returned by the web service + * @param uri the URI of the web service + * @param responseClass the class of the object returned by the web service + * @return the object returned by the web service + * @since Envoy v0.1-alpha + */ + private T get(String uri, Class responseClass) { javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client.target(String - .format("%s:%d/envoy-server/rest/message/receive?userId=%d", config.getServer(), config.getPort(), userId)); + WebTarget target = client.target(uri); Response response = target.request("application/xml").get(); - Messages unreadMessages = response.readEntity(Messages.class); + T responseObject = response.readEntity(responseClass); System.out.println("Response code: " + response.getStatus()); response.close(); client.close(); - return unreadMessages; + return responseObject; + } + + /** + * Wraps one or more {@link Message} objects into a {@link Messages} object. + * + * @param messages the {@link Message} objects to wrap + * @return {@link Messages} object with all messages as its children + * @since Envoy v0.1-alpha + */ + private Messages wrapMessages(Message... messages) { + Messages wrapper = objectFactory.createMessages(); + wrapper.getMessage().addAll(Arrays.asList(messages)); + return wrapper; } /** * @return the sender object that represents this client - * @since Envoy 0.1 + * @since Envoy v0.1-alpha */ public User getSender() { return sender; } From 60c8b09b372e4d8e5f8f63246a2dbbe2a648839e Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 27 Oct 2019 17:25:58 +0100 Subject: [PATCH 039/474] Added ChatSynchronizer class to store chats locally --- .gitignore | 1 + src/main/java/envoy/client/Chat.java | 6 +- .../java/envoy/client/ChatSynchronizer.java | 47 +++++++++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 59 ++++++++++++++----- src/main/java/envoy/client/ui/Startup.java | 3 +- 5 files changed, 98 insertions(+), 18 deletions(-) create mode 100644 src/main/java/envoy/client/ChatSynchronizer.java diff --git a/.gitignore b/.gitignore index b83d222..7836310 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target/ +/local_chats.db diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index 3f48c7c..6dcb35a 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -1,12 +1,16 @@ package envoy.client; +import java.io.Serializable; + import javax.swing.DefaultListModel; import envoy.schema.Message; import envoy.schema.User; -public class Chat { +public class Chat implements Serializable { + private static final long serialVersionUID = -7751248474547242056L; + private User recipient; private DefaultListModel model = new DefaultListModel<>(); diff --git a/src/main/java/envoy/client/ChatSynchronizer.java b/src/main/java/envoy/client/ChatSynchronizer.java new file mode 100644 index 0000000..0f7322f --- /dev/null +++ b/src/main/java/envoy/client/ChatSynchronizer.java @@ -0,0 +1,47 @@ +package envoy.client; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * Project: envoy-client
+ * File: ChatSynchronizer.java
+ * Created: 27.10.2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.1-alpha + */ +public class ChatSynchronizer { + + private File localDB; + private List chats = new ArrayList<>(); + + public ChatSynchronizer(String localDBPath) { + localDB = new File(localDBPath); + if (localDB.exists() && !localDB.isDirectory()) loadFromLocalDB(); + } + + public void saveToLocalDB() { + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) { + out.writeObject(chats); + } catch(IOException ex) { + ex.printStackTrace(); + } + } + + @SuppressWarnings("unchecked") + private void loadFromLocalDB() { + try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(localDB))) { + Object obj = in.readObject(); + if (obj instanceof ArrayList) chats = (ArrayList) obj; + } catch (ClassNotFoundException | IOException e) {} + } + + public List getChats() { return chats; } +} diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index dd7ff5e..4f5256e 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -6,8 +6,8 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; -import java.util.ArrayList; -import java.util.List; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -24,6 +24,7 @@ import javax.swing.Timer; import javax.swing.border.EmptyBorder; import envoy.client.Chat; +import envoy.client.ChatSynchronizer; import envoy.client.Client; import envoy.schema.Message; import envoy.schema.Messages; @@ -46,20 +47,30 @@ public class ChatWindow extends JFrame { private JPanel contentPane = new JPanel(); - private Client client; + private Client client; + private ChatSynchronizer chatSynchronizer; - private JList userList = new JList<>(); - private List partnerChatList = new ArrayList(); + private JList userList = new JList<>(); private Chat currentChat; - public ChatWindow(Client client) { - this.client = client; + public ChatWindow(Client client, ChatSynchronizer chatSynchronizer) { + this.client = client; + this.chatSynchronizer = chatSynchronizer; setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); setTitle("Envoy"); setLocationRelativeTo(null); + // Save chats when window closes + addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + chatSynchronizer.saveToLocalDB(); + } + }); + contentPane.setBackground(new Color(0, 0, 0)); contentPane.setForeground(Color.white); contentPane.setBorder(new EmptyBorder(0, 5, 0, 0)); @@ -138,7 +149,8 @@ public class ChatWindow extends JFrame { postButton.addActionListener((evt) -> { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", + JOptionPane.INFORMATION_MESSAGE); return; } @@ -158,8 +170,7 @@ public class ChatWindow extends JFrame { } catch (Exception e) { JOptionPane.showMessageDialog(this, "An exception occured while sending a message. See the log for more details.", - "Exception occured", - JOptionPane.ERROR_MESSAGE); + "Exception occured", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } }); @@ -186,12 +197,18 @@ public class ChatWindow extends JFrame { userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); userList.addListSelectionListener((listSelectionEvent) -> { if (!listSelectionEvent.getValueIsAdjusting()) { - @SuppressWarnings("unchecked") + @SuppressWarnings( + "unchecked" + ) final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = partnerChatList.stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); + currentChat = chatSynchronizer.getChats() + .stream() + .filter(chat -> chat.getRecipient().getID() == user.getID()) + .findFirst() + .get(); client.setRecipient(user); @@ -232,7 +249,15 @@ public class ChatWindow extends JFrame { new Thread(() -> { Users users = client.getUsersListXml(); DefaultListModel userListModel = new DefaultListModel<>(); - users.getUser().forEach(user -> { userListModel.addElement(user); partnerChatList.add(new Chat(user)); }); + users.getUser().forEach(user -> { + userListModel.addElement(user); + + // Check if user exists in local DB + if (chatSynchronizer.getChats() + .stream() + .filter(c -> c.getRecipient().getID() == user.getID()) + .count() == 0) chatSynchronizer.getChats().add(new Chat(user)); + }); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); }).start(); } @@ -247,9 +272,11 @@ public class ChatWindow extends JFrame { new Timer(timeout, (evt) -> { Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); for (int i = 0; i < unreadMessages.getMessage().size(); i++) - for (int j = 0; j < partnerChatList.size(); j++) - if (partnerChatList.get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) - partnerChatList.get(j).appendMessage(unreadMessages.getMessage().get(i)); + for (int j = 0; j < chatSynchronizer.getChats().size(); j++) + if (chatSynchronizer.getChats().get(j) + .getRecipient() + .getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) + chatSynchronizer.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); }).start(); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index b525861..e664aa8 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -6,6 +6,7 @@ import java.util.Properties; import javax.swing.JOptionPane; +import envoy.client.ChatSynchronizer; import envoy.client.Client; import envoy.client.Config; @@ -51,7 +52,7 @@ public class Startup { EventQueue.invokeLater(() -> { try { - ChatWindow frame = new ChatWindow(client); + ChatWindow frame = new ChatWindow(client, new ChatSynchronizer("local_chats.db")); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); From 16a3d32875602d61ff9e38dc086f9c8c90da8356 Mon Sep 17 00:00:00 2001 From: delvh Date: Sun, 27 Oct 2019 20:23:36 +0100 Subject: [PATCH 040/474] Updated Javadoc for the whole Repository Aside from the files ChatWindow, Client and SettingsScreen, theirs is already in my commit in f/settings --- src/main/java/envoy/client/Chat.java | 21 ++++++++++ src/main/java/envoy/client/Config.java | 42 +++++++++++++++---- .../envoy/client/ui/MessageListRenderer.java | 6 ++- src/main/java/envoy/client/ui/Startup.java | 2 +- .../envoy/client/ui/UserListRenderer.java | 5 ++- 5 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index 3f48c7c..19ad291 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -10,11 +10,32 @@ public class Chat { private User recipient; private DefaultListModel model = new DefaultListModel<>(); + /** + * Provides the list of messages that the recipient receives.
+ * Saves the Messages in the corresponding chat at that Point. + * + * @param recipient the user who receives the messages + * @since Envoy v0.1-alpha + */ public Chat(User recipient) { this.recipient = recipient; } + /** + * @return the recipient of a message + * @since Envoy v0.1-alpha + */ public User getRecipient() { return recipient; } + /** + * Adds the received message at the current Point in the current chat + * + * @param message the message to add in said chat + * @since Envoy v0.1-alpha + */ public void appendMessage(Message message) { model.addElement(message); } + /** + * @return all messages in the current chat + * @since Envoy v0.1-alpha + */ public DefaultListModel getModel() { return model; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index fda0f97..ee9cf31 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -8,7 +8,7 @@ import java.util.Properties; * Created: 12 Oct 2019
* * @author Kai S. K. Engelbart - * @since Envoy 0.1 + * @since Envoy v0.1-alpha */ public class Config { @@ -19,8 +19,9 @@ public class Config { * Defaults to the {@code server.properties} file for information. * * - * @param properties - The two options for internet connection server and port - * @since Envoy 0.1 + * @param properties - The two options for internet connection + * server and port + * @since Envoy v0.1-alpha */ public void load(Properties properties) { if (properties.containsKey("server")) server = properties.getProperty("server"); @@ -28,11 +29,12 @@ public class Config { } /** - * Sets the server and the port via command line properties --server/ -s and --port/ -p. + * Sets the server and the port via command line properties --server/ -s and + * --port/ -p. * * @param args {@code --server} or {@code -s} followed by the specified URL - * and {@code --port} or {@code -p} followed by a 4-digit Integer - * @since Envoy 0.1 + * and {@code --port} or {@code -p} followed by a 4-digit Integer + * @since Envoy v0.1-alpha */ public void load(String[] args) { for (int i = 0; i < args.length; i++) @@ -48,13 +50,39 @@ public class Config { } } + /** + * @return true if server and port are known. + * @since Envoy v0.1-alpha + */ public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0; } + /** + * @return the URL of our website + * @since Envoy v0.1-alpha + */ public String getServer() { return server; } + /** + * Changes the default URL. + * Exclusively meant for developing reasons. (localhost) + * + * @param server the URL where wish to host Envoy + * @since Envoy v0.1-alpha + */ public void setServer(String server) { this.server = server; } + /** + * @return the port at which Envoy is located in the Server + * @since Envoy v0.1-alpha + */ public int getPort() { return port; } + /** + * Changes the default port. + * Exclusively meant for developing reasons. (localhost) + * + * @param port the port where we wish to connect to {@code Envoy}. + * @since Envoy v0.1-alpha + */ public void setPort(int port) { this.port = port; } -} +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index a61ae5f..4490b69 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -10,11 +10,15 @@ import javax.swing.ListCellRenderer; import envoy.schema.Message; /** + * Defines how a message is displayed.
+ *
+ * * Project: envoy-client
* File: UserListRenderer.java
* Created: 19 Oct 2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.1-alpha */ public class MessageListRenderer extends JLabel implements ListCellRenderer { @@ -44,4 +48,4 @@ public class MessageListRenderer extends JLabel implements ListCellRendererenvoy-client
* File: UserListRenderer.java
* Created: 12 Oct 2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.1-alpha */ public class UserListRenderer extends JLabel implements ListCellRenderer { @@ -38,4 +41,4 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { return this; } -} +} \ No newline at end of file From 6e4b4e4d4eb19926567a1d884d97f2e5a1cf0b72 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 27 Oct 2019 21:40:40 +0100 Subject: [PATCH 041/474] Renamed ChatSynchronizer to LocalDB, added user-specific files --- src/main/java/envoy/client/Config.java | 29 +++++++++++----- .../{ChatSynchronizer.java => LocalDB.java} | 34 ++++++++++++++----- src/main/java/envoy/client/ui/ChatWindow.java | 22 ++++++------ src/main/java/envoy/client/ui/Startup.java | 19 ++++++++--- src/main/resources/client.properties | 3 ++ src/main/resources/server.properties | 2 -- 6 files changed, 74 insertions(+), 35 deletions(-) rename src/main/java/envoy/client/{ChatSynchronizer.java => LocalDB.java} (50%) create mode 100644 src/main/resources/client.properties delete mode 100644 src/main/resources/server.properties diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index fda0f97..19a5843 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -1,5 +1,6 @@ package envoy.client; +import java.io.File; import java.util.Properties; /** @@ -14,25 +15,28 @@ public class Config { private String server; private int port; + private File localDB; /** - * Defaults to the {@code server.properties} file for information. + * Defaults to the {@code client.properties} file for information. * - * - * @param properties - The two options for internet connection server and port - * @since Envoy 0.1 + * @param properties a {@link Properties} object containing information about + * the server and port, as well as the path to the local + * database + * @since Envoy v0.1-alpha */ public void load(Properties properties) { if (properties.containsKey("server")) server = properties.getProperty("server"); if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); + localDB = new File(properties.getProperty("localDB", ".\\localDB")); } /** - * Sets the server and the port via command line properties --server/ -s and --port/ -p. + * Sets the server, port and localDB path via command line properties --server / + * -s, --port / -p and --localDB / -db. * - * @param args {@code --server} or {@code -s} followed by the specified URL - * and {@code --port} or {@code -p} followed by a 4-digit Integer - * @since Envoy 0.1 + * @param args the command line arguments to parse + * @since Envoy v0.1-alpha */ public void load(String[] args) { for (int i = 0; i < args.length; i++) @@ -45,10 +49,13 @@ public class Config { case "-p": port = Integer.parseInt(args[++i]); break; + case "--localDB": + case "-db": + localDB = new File(args[++i]); } } - public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0; } + public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; } public String getServer() { return server; } @@ -57,4 +64,8 @@ public class Config { public int getPort() { return port; } public void setPort(int port) { this.port = port; } + + public File getLocalDB() { return localDB; } + + public void setLocalDB(File localDB) { this.localDB = localDB; } } diff --git a/src/main/java/envoy/client/ChatSynchronizer.java b/src/main/java/envoy/client/LocalDB.java similarity index 50% rename from src/main/java/envoy/client/ChatSynchronizer.java rename to src/main/java/envoy/client/LocalDB.java index 0f7322f..5a06a02 100644 --- a/src/main/java/envoy/client/ChatSynchronizer.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -9,38 +9,54 @@ import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; +import envoy.exception.EnvoyException; +import envoy.schema.User; + /** * Project: envoy-client
- * File: ChatSynchronizer.java
+ * File: LocalDB.java
* Created: 27.10.2019
* * @author Kai S. K. Engelbart * @since Envoy v0.1-alpha */ -public class ChatSynchronizer { +public class LocalDB { private File localDB; + private User sender; private List chats = new ArrayList<>(); - public ChatSynchronizer(String localDBPath) { - localDB = new File(localDBPath); - if (localDB.exists() && !localDB.isDirectory()) loadFromLocalDB(); + public LocalDB(User sender) { this.sender = sender; } + + public void initializeDBFile(File localDBDir) throws EnvoyException { + if (localDBDir.exists() && !localDBDir.isDirectory()) + throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); + localDB = new File(localDBDir, sender.getID() + ".db"); + if (localDB.exists()) loadFromLocalDB(); } public void saveToLocalDB() { + try { + localDB.getParentFile().mkdirs(); + localDB.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) { out.writeObject(chats); - } catch(IOException ex) { + } catch (IOException ex) { ex.printStackTrace(); } } - + @SuppressWarnings("unchecked") - private void loadFromLocalDB() { + private void loadFromLocalDB() throws EnvoyException { try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(localDB))) { Object obj = in.readObject(); if (obj instanceof ArrayList) chats = (ArrayList) obj; - } catch (ClassNotFoundException | IOException e) {} + } catch (ClassNotFoundException | IOException e) { + throw new EnvoyException(e); + } } public List getChats() { return chats; } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 4f5256e..8feb3ac 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -24,8 +24,8 @@ import javax.swing.Timer; import javax.swing.border.EmptyBorder; import envoy.client.Chat; -import envoy.client.ChatSynchronizer; import envoy.client.Client; +import envoy.client.LocalDB; import envoy.schema.Message; import envoy.schema.Messages; import envoy.schema.User; @@ -48,14 +48,14 @@ public class ChatWindow extends JFrame { private JPanel contentPane = new JPanel(); private Client client; - private ChatSynchronizer chatSynchronizer; + private LocalDB localDB; private JList userList = new JList<>(); private Chat currentChat; - public ChatWindow(Client client, ChatSynchronizer chatSynchronizer) { + public ChatWindow(Client client, LocalDB localDB) { this.client = client; - this.chatSynchronizer = chatSynchronizer; + this.localDB = localDB; setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); @@ -67,7 +67,7 @@ public class ChatWindow extends JFrame { @Override public void windowClosing(WindowEvent e) { - chatSynchronizer.saveToLocalDB(); + localDB.saveToLocalDB(); } }); @@ -204,7 +204,7 @@ public class ChatWindow extends JFrame { final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = chatSynchronizer.getChats() + currentChat = localDB.getChats() .stream() .filter(chat -> chat.getRecipient().getID() == user.getID()) .findFirst() @@ -253,10 +253,10 @@ public class ChatWindow extends JFrame { userListModel.addElement(user); // Check if user exists in local DB - if (chatSynchronizer.getChats() + if (localDB.getChats() .stream() .filter(c -> c.getRecipient().getID() == user.getID()) - .count() == 0) chatSynchronizer.getChats().add(new Chat(user)); + .count() == 0) localDB.getChats().add(new Chat(user)); }); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); }).start(); @@ -272,11 +272,11 @@ public class ChatWindow extends JFrame { new Timer(timeout, (evt) -> { Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); for (int i = 0; i < unreadMessages.getMessage().size(); i++) - for (int j = 0; j < chatSynchronizer.getChats().size(); j++) - if (chatSynchronizer.getChats().get(j) + for (int j = 0; j < localDB.getChats().size(); j++) + if (localDB.getChats().get(j) .getRecipient() .getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) - chatSynchronizer.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); + localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); }).start(); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index e664aa8..d494536 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -6,9 +6,10 @@ import java.util.Properties; import javax.swing.JOptionPane; -import envoy.client.ChatSynchronizer; import envoy.client.Client; import envoy.client.Config; +import envoy.client.LocalDB; +import envoy.exception.EnvoyException; /** * Starts the Envoy client and prompts the user to enter their name. @@ -31,7 +32,7 @@ public class Startup { ClassLoader loader = Thread.currentThread().getContextClassLoader(); try { Properties configProperties = new Properties(); - configProperties.load(loader.getResourceAsStream("server.properties")); + configProperties.load(loader.getResourceAsStream("client.properties")); config.load(configProperties); } catch (IOException e) { e.printStackTrace(); @@ -48,11 +49,21 @@ public class Startup { System.err.println("User name is not set or empty. Exiting..."); System.exit(1); } - Client client = new Client(config, userName); + Client client = new Client(config, userName); + LocalDB localDB = new LocalDB(client.getSender()); + try { + localDB.initializeDBFile(config.getLocalDB()); + } catch (EnvoyException e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(null, + "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", + "Local DB error", + JOptionPane.WARNING_MESSAGE); + } EventQueue.invokeLater(() -> { try { - ChatWindow frame = new ChatWindow(client, new ChatSynchronizer("local_chats.db")); + ChatWindow frame = new ChatWindow(client, localDB); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/resources/client.properties b/src/main/resources/client.properties new file mode 100644 index 0000000..2641927 --- /dev/null +++ b/src/main/resources/client.properties @@ -0,0 +1,3 @@ +server=http://kske.feste-ip.net +port=43315 +localDB=.\\localDB diff --git a/src/main/resources/server.properties b/src/main/resources/server.properties deleted file mode 100644 index 6b0ae8f..0000000 --- a/src/main/resources/server.properties +++ /dev/null @@ -1,2 +0,0 @@ -server=http://kske.feste-ip.net -port=43315 \ No newline at end of file From 57b3a57452d150d83daff5b7a03257761f79ba9d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 30 Oct 2019 06:16:44 +0100 Subject: [PATCH 042/474] Updated .gitignore to include localDB --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7836310..e12b13a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ /target/ -/local_chats.db +/localDB/ \ No newline at end of file From 910896152268c7f968162042f974df63347f1c2e Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 30 Oct 2019 06:19:50 +0100 Subject: [PATCH 043/474] Fixed formatting --- src/main/java/envoy/client/ui/ChatWindow.java | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 8feb3ac..5f79b13 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -47,14 +47,14 @@ public class ChatWindow extends JFrame { private JPanel contentPane = new JPanel(); - private Client client; + private Client client; private LocalDB localDB; private JList userList = new JList<>(); private Chat currentChat; public ChatWindow(Client client, LocalDB localDB) { - this.client = client; + this.client = client; this.localDB = localDB; setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -66,11 +66,9 @@ public class ChatWindow extends JFrame { addWindowListener(new WindowAdapter() { @Override - public void windowClosing(WindowEvent e) { - localDB.saveToLocalDB(); - } + public void windowClosing(WindowEvent e) { localDB.saveToLocalDB(); } }); - + contentPane.setBackground(new Color(0, 0, 0)); contentPane.setForeground(Color.white); contentPane.setBorder(new EmptyBorder(0, 5, 0, 0)); @@ -149,8 +147,7 @@ public class ChatWindow extends JFrame { postButton.addActionListener((evt) -> { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", - JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); return; } @@ -170,7 +167,8 @@ public class ChatWindow extends JFrame { } catch (Exception e) { JOptionPane.showMessageDialog(this, "An exception occured while sending a message. See the log for more details.", - "Exception occured", JOptionPane.ERROR_MESSAGE); + "Exception occured", + JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } }); @@ -197,18 +195,12 @@ public class ChatWindow extends JFrame { userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); userList.addListSelectionListener((listSelectionEvent) -> { if (!listSelectionEvent.getValueIsAdjusting()) { - @SuppressWarnings( - "unchecked" - ) + @SuppressWarnings("unchecked") final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = localDB.getChats() - .stream() - .filter(chat -> chat.getRecipient().getID() == user.getID()) - .findFirst() - .get(); + currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); client.setRecipient(user); @@ -253,10 +245,8 @@ public class ChatWindow extends JFrame { userListModel.addElement(user); // Check if user exists in local DB - if (localDB.getChats() - .stream() - .filter(c -> c.getRecipient().getID() == user.getID()) - .count() == 0) localDB.getChats().add(new Chat(user)); + if (localDB.getChats().stream().filter(c -> c.getRecipient().getID() == user.getID()).count() == 0) + localDB.getChats().add(new Chat(user)); }); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); }).start(); @@ -273,9 +263,7 @@ public class ChatWindow extends JFrame { Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); for (int i = 0; i < unreadMessages.getMessage().size(); i++) for (int j = 0; j < localDB.getChats().size(); j++) - if (localDB.getChats().get(j) - .getRecipient() - .getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) + if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); }).start(); } From 46521d8230100b783faea624465be2bd1dd66535 Mon Sep 17 00:00:00 2001 From: delvh Date: Wed, 30 Oct 2019 07:45:33 +0100 Subject: [PATCH 044/474] Updated Javadoc in Config File --- src/main/java/envoy/client/Config.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 0ffcca8..d6bf106 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -52,6 +52,7 @@ public class Config { case "--localDB": case "-db": localDB = new File(args[++i]); + break; } } @@ -91,7 +92,18 @@ public class Config { */ public void setPort(int port) { this.port = port; } + /** + *@return the current local database that is held for that user + *@since Envoy v0.1-alpha + **/ public File getLocalDB() { return localDB; } + /** + *Changes the default local database. + *Exclusively meant for developing reasons. + * + *@param the local database object to set + *@since Envoy v0.1-alpha + **/ public void setLocalDB(File localDB) { this.localDB = localDB; } -} \ No newline at end of file +} From d739f7a4458eed515d0539793a4c533874b68fb5 Mon Sep 17 00:00:00 2001 From: delvh Date: Wed, 30 Oct 2019 08:10:40 +0100 Subject: [PATCH 045/474] Updated Javadoc for LocalDB File --- src/main/java/envoy/client/LocalDB.java | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 5a06a02..d6a257a 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -26,8 +26,22 @@ public class LocalDB { private User sender; private List chats = new ArrayList<>(); + /** + *Constructs an empty local database. + * + *@param sender the user who logs in + *@since Envoy v0.1-alpha + **/ public LocalDB(User sender) { this.sender = sender; } + /** + *Initialises the local database and fills it with values + *if the user already sent/ received a message.
+ * + *@param localDBDir the directory where we wish to save/load the database from. + *@throws EnvoyException if the directory selected is not an actual directory. + *@since Envoy v0.1-alpha + **/ public void initializeDBFile(File localDBDir) throws EnvoyException { if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); @@ -35,20 +49,34 @@ public class LocalDB { if (localDB.exists()) loadFromLocalDB(); } + /** + *Saves the database into a file for future use. + * + *@throws IOException if something went wrong during saving + *@since Envoy v0.1-alpha + **/ public void saveToLocalDB() { try { localDB.getParentFile().mkdirs(); localDB.createNewFile(); } catch (IOException e) { e.printStackTrace(); + System.err.println("unable to save the messages"); } try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) { out.writeObject(chats); } catch (IOException ex) { ex.printStackTrace(); + System.err.println("unable to save the messages"); } } + /** + *Loads all chats saved by Envoy for the user.
+ * + *@throws EnvoyException if something fails while loading. + *@since Envoy v0.1-alpha + **/ @SuppressWarnings("unchecked") private void loadFromLocalDB() throws EnvoyException { try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(localDB))) { @@ -59,5 +87,9 @@ public class LocalDB { } } + /** + *@return all chats that the user has saved + *@since Envoy v0.1-alpha + **/ public List getChats() { return chats; } } From 316936a1f85c91abf8ec5f64e1b8812de665740c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 30 Oct 2019 17:01:55 +0100 Subject: [PATCH 046/474] Fixed Javadoc formatting and spelling --- src/main/java/envoy/client/Config.java | 37 +++++++++--------- src/main/java/envoy/client/LocalDB.java | 51 +++++++++++++------------ 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index d6bf106..1d107ca 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -52,58 +52,57 @@ public class Config { case "--localDB": case "-db": localDB = new File(args[++i]); - break; } } - /** - * @return {@code true} if server, port andd localDB directory are known. + /** + * @return {@code true} if server, port and localDB directory are known. * @since Envoy v0.1-alpha */ public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; } /** - * @return the URL of our website + * @return the host name of the Envoy server * @since Envoy v0.1-alpha */ public String getServer() { return server; } /** - * Changes the default URL. - * Exclusively meant for developing reasons. (localhost) + * Changes the default server host name. + * Exclusively intended for development purposes. * - * @param server the URL where wish to host Envoy + * @param server the host name of the Envoy server * @since Envoy v0.1-alpha */ public void setServer(String server) { this.server = server; } /** - * @return the port at which Envoy is located in the Server + * @return the port at which the Envoy server is located on the host * @since Envoy v0.1-alpha */ public int getPort() { return port; } /** * Changes the default port. - * Exclusively meant for developing reasons. (localhost) + * Exclusively intended for development purposes. * - * @param port the port where we wish to connect to {@code Envoy}. + * @param port the port where an Envoy server is located * @since Envoy v0.1-alpha */ public void setPort(int port) { this.port = port; } /** - *@return the current local database that is held for that user - *@since Envoy v0.1-alpha - **/ + * @return the local database specific to the client user + * @since Envoy v0.1-alpha + **/ public File getLocalDB() { return localDB; } /** - *Changes the default local database. - *Exclusively meant for developing reasons. - * - *@param the local database object to set - *@since Envoy v0.1-alpha - **/ + * Changes the default local database. + * Exclusively intended for development purposes. + * + * @param the file containing the local database + * @since Envoy v0.1-alpha + **/ public void setLocalDB(File localDB) { this.localDB = localDB; } } diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index d6a257a..d7b3409 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -27,21 +27,21 @@ public class LocalDB { private List chats = new ArrayList<>(); /** - *Constructs an empty local database. - * - *@param sender the user who logs in - *@since Envoy v0.1-alpha - **/ + * Constructs an empty local database. + * + * @param sender the user that is logged in with this client + * @since Envoy v0.1-alpha + **/ public LocalDB(User sender) { this.sender = sender; } /** - *Initialises the local database and fills it with values - *if the user already sent/ received a message.
- * - *@param localDBDir the directory where we wish to save/load the database from. - *@throws EnvoyException if the directory selected is not an actual directory. - *@since Envoy v0.1-alpha - **/ + * Initializes the local database and fills it with values + * if the user has already sent or received messages. + * + * @param localDBDir the directory where we wish to save/load the database from. + * @throws EnvoyException if the directory selected is not an actual directory. + * @since Envoy v0.1-alpha + **/ public void initializeDBFile(File localDBDir) throws EnvoyException { if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); @@ -50,11 +50,11 @@ public class LocalDB { } /** - *Saves the database into a file for future use. - * - *@throws IOException if something went wrong during saving - *@since Envoy v0.1-alpha - **/ + * Saves the database into a file for future use. + * + * @throws IOException if something went wrong during saving + * @since Envoy v0.1-alpha + **/ public void saveToLocalDB() { try { localDB.getParentFile().mkdirs(); @@ -72,11 +72,11 @@ public class LocalDB { } /** - *Loads all chats saved by Envoy for the user.
- * - *@throws EnvoyException if something fails while loading. - *@since Envoy v0.1-alpha - **/ + * Loads all chats saved by Envoy for the client user. + * + * @throws EnvoyException if something fails while loading. + * @since Envoy v0.1-alpha + **/ @SuppressWarnings("unchecked") private void loadFromLocalDB() throws EnvoyException { try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(localDB))) { @@ -88,8 +88,9 @@ public class LocalDB { } /** - *@return all chats that the user has saved - *@since Envoy v0.1-alpha - **/ + * @return all saves {@link Chat} objects that list the client user as the + * sender + * @since Envoy v0.1-alpha + **/ public List getChats() { return chats; } } From 4adc23d9025b08837b9f9f6f9dc2baf118487e31 Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 31 Oct 2019 22:11:50 +0100 Subject: [PATCH 047/474] Added automatic line separation and Keylistener for posting Improvements yet to be made (help wanted!): * automatic line separation does not work * automatic line separation needs a case for insertion of a String * Keylistener for Posting does not work * Method for listening to multiple keys needed (ctrl+enter) * A template Settings screen was added, has yet to be polished --- src/main/java/envoy/client/Chat.java | 2 +- src/main/java/envoy/client/Client.java | 37 +++-- src/main/java/envoy/client/Config.java | 4 +- src/main/java/envoy/client/LocalDB.java | 20 ++- src/main/java/envoy/client/ui/ChatWindow.java | 113 +++++++++++-- .../java/envoy/client/ui/SettingsScreen.java | 156 ++++++++++++++++++ 6 files changed, 301 insertions(+), 31 deletions(-) create mode 100644 src/main/java/envoy/client/ui/SettingsScreen.java diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index abeb226..da35bd3 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -10,7 +10,7 @@ import envoy.schema.User; public class Chat implements Serializable { private static final long serialVersionUID = -7751248474547242056L; - + private User recipient; private DefaultListModel model = new DefaultListModel<>(); diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 0ebce3c..120d7dc 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -28,9 +28,8 @@ import envoy.schema.Users; * @author Kai S. K. Engelbart * @author Maximilian Käfer * @author Leon Hofmeister - * @since Envoy 0.1 + * @since Envoy v0.1-alpha */ - public class Client { private ObjectFactory objectFactory = new ObjectFactory(); @@ -53,9 +52,8 @@ public class Client { * Because sending a request is a blocking operation, it is executed * asynchronously. * - * @param sender name of the sender - * @param recipient name of the recipient - * @param textContent content (text) of the message + * @param message the {@link Message} we want to send + * @since Envoy v0.1-alpha */ public void sendMessage(Message message) { new Thread(() -> { @@ -90,6 +88,7 @@ public class Client { * * @param textContent The content (text) of the message * @return prepared {@link Message} object + * @since Envoy v0.1-alpha */ public Message createMessage(String textContent) { Message.MetaData metaData = objectFactory.createMessageMetaData(); @@ -109,22 +108,28 @@ public class Client { return message; } - public Users getUsersListXml() { return get(String.format("%s:%d/envoy-server/rest/user", config.getServer(), config.getPort()), Users.class); } + public Users getUsersListXml() { + return get(String.format("%s:%d/envoy-server/rest/user", config.getServer(), config.getPort()), Users.class); + } public Messages getUnreadMessages(long userId) { - return get(String.format("%s:%d/envoy-server/rest/message/receive?userId=%d", config.getServer(), config.getPort(), userId), Messages.class); + return get(String + .format("%s:%d/envoy-server/rest/message/receive?userId=%d", config.getServer(), config.getPort(), userId), + Messages.class); } /** - * Returns a {@link User} with a specific name by name. + * Returns a {@link User} with a specific id by name. * * @param name - the name of the {@link User} * @return a {@link User} with the specified name * @since Envoy v0.1-alpha */ private User getUser(String name) { - return get(String.format("%s:%d/envoy-server/rest/user/sender?name=%s", config.getServer(), config.getPort(), name), Users.class).getUser() - .get(0); + return get( + String + .format("%s:%d/envoy-server/rest/user/sender?name=%s", config.getServer(), config.getPort(), name), + Users.class).getUser().get(0); } /** @@ -166,9 +171,21 @@ public class Client { */ public User getSender() { return sender; } + /** + * @return the recipient of a message. + * @since Envoy v0.1-alpha + */ public User getRecipient() { return recipient; } + /** + * @param recipient the recipient to set + * @since Envoy v0.1-alpha + */ public void setRecipient(User recipient) { this.recipient = recipient; } + /** + * @return true, if a recipient is selected + * @since Envoy v0.1-alpha + */ public boolean hasRecipient() { return recipient != null; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 1d107ca..bfa1e57 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -59,7 +59,9 @@ public class Config { * @return {@code true} if server, port and localDB directory are known. * @since Envoy v0.1-alpha */ - public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; } + public boolean isInitialized() { + return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; + } /** * @return the host name of the Envoy server diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index d7b3409..1bab251 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -23,16 +23,16 @@ import envoy.schema.User; public class LocalDB { private File localDB; - private User sender; + private User client; private List chats = new ArrayList<>(); /** * Constructs an empty local database. * - * @param sender the user that is logged in with this client + * @param client the user that is logged in with this client * @since Envoy v0.1-alpha **/ - public LocalDB(User sender) { this.sender = sender; } + public LocalDB(User sender) { this.client = sender; } /** * Initializes the local database and fills it with values @@ -43,9 +43,9 @@ public class LocalDB { * @since Envoy v0.1-alpha **/ public void initializeDBFile(File localDBDir) throws EnvoyException { - if (localDBDir.exists() && !localDBDir.isDirectory()) - throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - localDB = new File(localDBDir, sender.getID() + ".db"); + if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException( + String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); + localDB = new File(localDBDir, client.getID() + ".db"); if (localDB.exists()) loadFromLocalDB(); } @@ -89,8 +89,14 @@ public class LocalDB { /** * @return all saves {@link Chat} objects that list the client user as the - * sender + * client * @since Envoy v0.1-alpha **/ public List getChats() { return chats; } + + /** + * @return the User who initialised the local Database + * @since Envoy v0.1-alpha + */ + public User getUser() { return client; } } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 5f79b13..f6625b5 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -6,6 +6,9 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; @@ -39,7 +42,7 @@ import envoy.schema.Users; * @author Kai S. K. Engelbart * @author Maximilian Käfer * @author Leon Hofmeister - * @since Envoy 0.1 + * @since Envoy v0.1-alpha */ public class ChatWindow extends JFrame { @@ -53,6 +56,8 @@ public class ChatWindow extends JFrame { private JList userList = new JList<>(); private Chat currentChat; + private String messageText; + public ChatWindow(Client client, LocalDB localDB) { this.client = client; this.localDB = localDB; @@ -77,7 +82,7 @@ public class ChatWindow extends JFrame { gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; - gbl_contentPane.rowWeights = new double[] { 0.05, 1, 0.07 }; + gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 }; contentPane.setLayout(gbl_contentPane); JList messageList = new JList<>(); @@ -114,6 +119,30 @@ public class ChatWindow extends JFrame { // Message enter field JTextArea messageEnterTextfield = new JTextArea(); + // checks for changed Message + messageEnterTextfield.addInputMethodListener(new InputMethodListener() { + + public void caretPositionChanged(InputMethodEvent arg0) {} + + public void inputMethodTextChanged(InputMethodEvent arg0) { + String message = messageEnterTextfield.getText(); + int messageSize = message.length(); + int lineSize = 45; + String[] tempString = message.split(System.getProperty("line.separator")); + int currentLineAmount = tempString.length; + int wantedLineAmount = Math.floorDiv(messageSize, lineSize); + if (currentLineAmount != wantedLineAmount) { + if (Math.abs(messageText.length() - messageSize) == 1 + && currentLineAmount == wantedLineAmount - 1) {// Check for "normal" Keystroke/Backspace + messageEnterTextfield.setText(transformLastSpace(message, wantedLineAmount, lineSize)); + } + } else {// That's the case if a group of chars was a)inserted or b)deleted + // TODO + } + messageText = message; + } + + }); messageEnterTextfield.setCaretColor(new Color(255, 255, 255)); messageEnterTextfield.setForeground(new Color(255, 255, 255)); messageEnterTextfield.setBackground(new Color(51, 51, 51)); @@ -122,17 +151,20 @@ public class ChatWindow extends JFrame { messageEnterTextfield.setFont(new Font("Arial", Font.PLAIN, 17)); messageEnterTextfield.setBorder(new EmptyBorder(5, 5, 5, 5)); - GridBagConstraints gbc_moveSelectionMessageEnterTextfield = new GridBagConstraints(); - gbc_moveSelectionMessageEnterTextfield.fill = GridBagConstraints.BOTH; - gbc_moveSelectionMessageEnterTextfield.gridx = 1; - gbc_moveSelectionMessageEnterTextfield.gridy = 2; + GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); + gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; + gbc_messageEnterTextfield.gridx = 1; + gbc_messageEnterTextfield.gridy = 2; - gbc_moveSelectionMessageEnterTextfield.insets = new Insets(10, 10, 10, 10); + gbc_messageEnterTextfield.insets = new Insets(10, 10, 10, 10); - contentPane.add(messageEnterTextfield, gbc_moveSelectionMessageEnterTextfield); + contentPane.add(messageEnterTextfield, gbc_messageEnterTextfield); // Post Button JButton postButton = new JButton("Post"); + if (SettingsScreen.isEnterToSend() == true) { postButton.setMnemonic(KeyEvent.VK_ENTER); } + // TODO: Other option to send only on "ctrl"+"enter" needs to be implemented. + // TODO: Difficult. Also above statement doesn't work! postButton.setForeground(new Color(255, 255, 255)); postButton.setBackground(new Color(102, 51, 153)); postButton.setBorderPainted(false); @@ -147,7 +179,10 @@ public class ChatWindow extends JFrame { postButton.addActionListener((evt) -> { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(this, + "Please select a recipient!", + "Cannot send message", + JOptionPane.INFORMATION_MESSAGE); return; } @@ -175,6 +210,31 @@ public class ChatWindow extends JFrame { contentPane.add(postButton, gbc_moveSelectionPostButton); + // Settings Button + JButton settingsButton = new JButton("Settings"); + settingsButton.setForeground(new Color(255, 255, 255)); + settingsButton.setBackground(new Color(102, 51, 153)); + settingsButton.setBorderPainted(false); + + GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); + + gbc_moveSelectionSettingsButton.fill = GridBagConstraints.BOTH; + gbc_moveSelectionSettingsButton.gridx = 2; + gbc_moveSelectionSettingsButton.gridy = 0; + + gbc_moveSelectionSettingsButton.insets = new Insets(10, 10, 10, 10); + + settingsButton.addActionListener((evt) -> { + try { + SettingsScreen.open(localDB.getUser().getName()); + } catch (Exception e) { + SettingsScreen.open(); + System.err.println("An Error occured while opening the Settings screen"); + e.printStackTrace(); + } + }); + contentPane.add(settingsButton, gbc_moveSelectionSettingsButton); + // Partner name display JTextPane textPane = new JTextPane(); textPane.setBackground(new Color(0, 0, 0)); @@ -200,7 +260,11 @@ public class ChatWindow extends JFrame { final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); + currentChat = localDB.getChats() + .stream() + .filter(chat -> chat.getRecipient().getID() == user.getID()) + .findFirst() + .get(); client.setRecipient(user); @@ -233,9 +297,31 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); } + /** + * takes care of too long or not needed lines in the message. + * + * @param message the message that is currently written in the textfield + * @param wantedLine the line at which we currently are positioned + * @param lineSize the amount of chars per line + * @return the transformed message + * @since Envoy v0.1-alpha + */ + private String transformLastSpace(String message, int wantedLine, int lineSize) { + int index = wantedLine * lineSize; + int lastSpace = message.lastIndexOf(" ", index); + if (index - lastSpace > lineSize) {// Fall Wort länger als Zeile + return message.substring(0, index) + System.getProperty("line.separator") + message.substring(index); + } else { + return message.substring(0, lastSpace - 1) + System.getProperty("line.separator") + + message.substring(lastSpace + 1); + } + } + /** * Initializes the elements of the user list by downloading them from the * server. + * + * @since Envoy v0.1-alpha */ private void loadUsersAndChats() { new Thread(() -> { @@ -257,14 +343,17 @@ public class ChatWindow extends JFrame { * * @param timeout the amount of time that passes between two requests sent to * the server + * @since Envoy v0.1-alpha */ private void startReceiverThread(int timeout) { new Timer(timeout, (evt) -> { Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); for (int i = 0; i < unreadMessages.getMessage().size(); i++) for (int j = 0; j < localDB.getChats().size(); j++) - if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) - localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); + if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessage() + .get(i) + .getMetaData() + .getSender()) localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); }).start(); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java new file mode 100644 index 0000000..7a4edab --- /dev/null +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -0,0 +1,156 @@ +package envoy.client.ui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FlowLayout; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; + +/** + * Project: envoy-client
+ * File: SettingsScreen.java
+ * Created: 31 Oct 2019
+ * + * @author Leon Hofmeister + */ +public class SettingsScreen extends JDialog { + + private static final long serialVersionUID = -4476913491263077107L; + private final JPanel contentPanel = new JPanel(); + public static boolean EnterToSend = true; + + // TODO: Add a JPanel with all the Information necessary: + // change (Picture,Username, Email, Password) and toggle(light/dark mode, + // "ctrl+enter"/"enter" + // to send a message directly) + /** + * Open the Settings screen. + * Only suited for Dev/Error mode. + * Avoid usage. + * + * @since Envoy v0.1-alpha + */ + public static void open() { + SettingsScreen dialog = new SettingsScreen(); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } + + /** + * Opens the Settings screen.
+ * Use preferreably since everyone is already initialised.
+ * It personalises the screen more. + * + * @param Username The name of the User + * @param Email The Email that is associated with that Account + * @since Envoy v0.1-alpha + */ + public static void open(String Username) {// , String Email) {AUSKLAMMERN, WENN ANMELDUNG PER + // EMAIL IMPLEMENTIERT IST! + SettingsScreen dialog = new SettingsScreen(Username); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } + + /** + * Builds the Settings screen.
+ * Use only as Dev/Error Mode.
+ * Avoid usage. + * + * @since Envoy v0.1-alpha + */ + public SettingsScreen() { + setBackground(Color.BLACK); + setBounds(100, 100, 450, 300); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBackground(Color.BLACK); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + contentPanel.setLayout(new BorderLayout(0, 0)); + { + JPanel buttonPane = new JPanel(); + buttonPane.setBackground(Color.BLACK); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + buttonPane.setLayout(new BorderLayout(0, 0)); + { + JButton okButton = new JButton("Save"); + okButton.setActionCommand("OK"); + buttonPane.add(okButton, BorderLayout.EAST); + getRootPane().setDefaultButton(okButton); + okButton.addActionListener((evt) -> { + // Hier später die Daten abspeichern, wenn Datenmodell implementiert ist + dispose(); + }); + } + { + JButton cancelButton = new JButton("Cancel"); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton, BorderLayout.WEST); + + cancelButton.addActionListener((evt) -> { dispose(); }); + } + } + } + + /** + * Builds the Settings screen.
+ * Use preferreably since everyone is already initialised.
+ * It personalises the screen more. + * + * @param Username The name of the User + * @param Email The Email that is associated with that Account + * @since Envoy v0.1-alpha + */ + public SettingsScreen(String Username) {// , String Email, String hashedPwd) {AUSKLAMMERN, WENN ANMELDUNG PER EMAIL + // IMPLEMENTIERT IST! + setBackground(Color.BLACK); + setBounds(100, 100, 450, 300); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBackground(Color.BLACK); + contentPanel.setLayout(new FlowLayout()); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + { + JPanel buttonPane = new JPanel(); + buttonPane.setBackground(Color.BLACK); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + buttonPane.setLayout(new BorderLayout(0, 0)); + { + JButton okButton = new JButton("Save"); + okButton.setActionCommand("OK"); + buttonPane.add(okButton, BorderLayout.EAST); + getRootPane().setDefaultButton(okButton); + okButton.addActionListener((evt) -> { + // Hier später die Daten abspeichern, wenn Datenmodell implementiert ist + dispose(); + }); + } + { + JButton cancelButton = new JButton("Cancel"); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton, BorderLayout.WEST); + + cancelButton.addActionListener((evt) -> { dispose(); }); + } + } + } + + /** + * @return true if Enter should be used to send a message + * @since Envoy v0.1-alpha + */ + public static boolean isEnterToSend() { return EnterToSend; } + + /** + * @param enterToSend
+ * toggles whether a message should be sent via + *
+ * buttonpress "enter" or "ctrl"+"enter" + * @since Envoy v0.1-alpha + */ + public static void setEnterToSend(boolean enterToSend) { EnterToSend = enterToSend; } + // TODO: Should be changed to private, but later to avoid warnings +} From ba0c588c77a4d97de9ae5a0704ed5c30cb9eb5db Mon Sep 17 00:00:00 2001 From: Maxi Date: Mon, 4 Nov 2019 23:10:53 +0100 Subject: [PATCH 048/474] Sync * Completely revised communication between client and server. * Added synchronization functionality. * Added Message State updates * Added UserStatus updates --- .classpath | 6 - src/main/java/envoy/client/Client.java | 436 +++++++++++++++--- src/main/java/envoy/client/ui/ChatWindow.java | 61 ++- .../envoy/client/ui/MessageListRenderer.java | 11 +- .../envoy/client/ui/UserListRenderer.java | 25 +- 5 files changed, 434 insertions(+), 105 deletions(-) diff --git a/.classpath b/.classpath index d2bc4e0..906bfce 100644 --- a/.classpath +++ b/.classpath @@ -18,12 +18,6 @@ - - - - - - diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 0ebce3c..b755c4a 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,8 +1,6 @@ package envoy.client; import java.time.Instant; -import java.util.Arrays; - import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; @@ -14,11 +12,10 @@ import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import envoy.schema.Message; -import envoy.schema.Message.MetaData.MessageState; -import envoy.schema.Messages; +import envoy.schema.Message.Metadata.MessageState; import envoy.schema.ObjectFactory; +import envoy.schema.Sync; import envoy.schema.User; -import envoy.schema.Users; /** * Project: envoy-client
@@ -38,6 +35,10 @@ public class Client { private Config config; private User sender, recipient; + private Sync unreadMessagesSync = objectFactory.createSync(); + public Sync sync = objectFactory.createSync(); + public Sync readMessages = objectFactory.createSync(); + public Client(Config config, String username) { this.config = config; try { @@ -46,43 +47,7 @@ public class Client { e.printStackTrace(); } sender = getUser(username); - } - - /** - * Sends a message with text content to the server.
- * Because sending a request is a blocking operation, it is executed - * asynchronously. - * - * @param sender name of the sender - * @param recipient name of the recipient - * @param textContent content (text) of the message - */ - public void sendMessage(Message message) { - new Thread(() -> { - // Wrap single message into messages list - Messages messages = wrapMessages(message); - - // Print message XML to console - JAXBContext jc; - try { - jc = JAXBContext.newInstance("envoy.schema"); - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - m.marshal(messages, System.out); - } catch (JAXBException e) { - e.printStackTrace(); - } - - // Send message - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client - .target(String.format("%s:%d/envoy-server/rest/message/send", config.getServer(), config.getPort())); - - Response response = target.request().post(Entity.entity(messages, "application/xml")); - System.out.println("Response code: " + response.getStatus()); - response.close(); - client.close(); - }).start(); + System.out.println("ID: " + sender.getID()); } /** @@ -92,7 +57,7 @@ public class Client { * @return prepared {@link Message} object */ public Message createMessage(String textContent) { - Message.MetaData metaData = objectFactory.createMessageMetaData(); + Message.Metadata metaData = objectFactory.createMessageMetadata(); metaData.setSender(sender.getID()); metaData.setRecipient(recipient.getID()); metaData.setState(MessageState.WAITING); @@ -103,16 +68,33 @@ public class Client { content.setText(textContent); Message message = objectFactory.createMessage(); - message.setMetaData(metaData); + message.setMetadata(metaData); message.getContent().add(content); return message; } + + /** + * Returns a {@link Sync} with all users on the server. + * @return Sync - List of all users on the server. + * @since Envoy v0.1-alpha + */ + public Sync getUsersListXml() { + Sync sendSync = objectFactory.createSync(); + User user = objectFactory.createUser(); + user.setID(-1); + sendSync.getUsers().add(user); - public Users getUsersListXml() { return get(String.format("%s:%d/envoy-server/rest/user", config.getServer(), config.getPort()), Users.class); } + javax.ws.rs.client.Client client = ClientBuilder.newClient(); + WebTarget target = client.target(String + .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0)); + + Response response = target.request().post(Entity.entity(sendSync, "application/xml")); + Sync returnSendSync = response.readEntity(Sync.class); + response.close(); + client.close(); + return returnSendSync; - public Messages getUnreadMessages(long userId) { - return get(String.format("%s:%d/envoy-server/rest/message/receive?userId=%d", config.getServer(), config.getPort(), userId), Messages.class); } /** @@ -123,52 +105,358 @@ public class Client { * @since Envoy v0.1-alpha */ private User getUser(String name) { - return get(String.format("%s:%d/envoy-server/rest/user/sender?name=%s", config.getServer(), config.getPort(), name), Users.class).getUser() - .get(0); - } + Sync senderSync = objectFactory.createSync(); + User user = objectFactory.createUser(); + user.setName(name); + senderSync.getUsers().add(user); - /** - * Invokes the GET method of a web service. - * - * @param the type of the object returned by the web service - * @param uri the URI of the web service - * @param responseClass the class of the object returned by the web service - * @return the object returned by the web service - * @since Envoy v0.1-alpha - */ - private T get(String uri, Class responseClass) { - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client.target(uri); - Response response = target.request("application/xml").get(); - T responseObject = response.readEntity(responseClass); - System.out.println("Response code: " + response.getStatus()); + javax.ws.rs.client.Client client = ClientBuilder.newClient(); + WebTarget target = client.target(String + .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0)); + + Response response = target.request().post(Entity.entity(senderSync, "application/xml")); + User returnSender = objectFactory.createUser(); + Sync returnSenderSync = response.readEntity(Sync.class); + if (returnSenderSync.getUsers().size() == 1) { + returnSender = returnSenderSync.getUsers().get(0); + } else { + System.out.println("ERROR exiting..."); + } response.close(); client.close(); - return responseObject; + return returnSender; } /** - * Wraps one or more {@link Message} objects into a {@link Messages} object. + * Sends the "sync" Sync Object to the server and gets a "returnSync" Sync + * Object as response.
+ * It is also used to get the own sender at the start of the client + * (Client sends "sync" Sync Object with single user in it(name: the name entered at login, id: 0, UserStatus:null))
+ * and to get a complete list of all users saved on the server. + * (Client sends "sync" Sync Object with single user in it(name: "" (empty), id: -1, UserStatus:null))
+ * This method also processes the response Sync Object.
+ * It sorts its users and messages by specific variables and does certain things + * with them.
+ *
+ * Messages:
+ * -State SENT: Update Local message(s) with State WAITING (add Message ID and + * change State to SENT). (server sends these informations to the client if + * message(s) with State WAITING were successfully sent to the server)
+ * -State RECEIVED, SenderID != 0: Adds the unread Messages returned from the + * server in the latest sync to the "unreadMessagesSync" Sync Object.
+ * -State RECEIVED, SenderID == 0: Update message(s) in localDB to state RECEIVED. + * (server sends these informations to the client if the other client received + * the message(s).)
+ * -State READ: Update message(s) in the LocalDB to state READ. (server sends these informations to the client if the other client read + * the message(s).)
+ *
+ * Users:
+ * Updating UserStatus of all users in LocalDB. (Server sends all users with their updated UserStatus to the client.)
* - * @param messages the {@link Message} objects to wrap - * @return {@link Messages} object with all messages as its children + * @param userId + * @param localDB * @since Envoy v0.1-alpha */ - private Messages wrapMessages(Message... messages) { - Messages wrapper = objectFactory.createMessages(); - wrapper.getMessage().addAll(Arrays.asList(messages)); - return wrapper; + public void sendSync(long userId, LocalDB localDB) { + new Thread(() -> { + // Print sync XML to console + JAXBContext jc; + try { + jc = JAXBContext.newInstance("envoy.schema"); + Marshaller m = jc.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.marshal(sync, System.out); + } catch (JAXBException e) { + e.printStackTrace(); + } + addWaitingMessagesToSync(localDB); + + getSentStateMessagesFromLocalDB(localDB); + for (int i = 0; i < readMessages.getMessages().size(); i++) { + sync.getMessages().add(readMessages.getMessages().get(i)); + } + readMessages.getMessages().clear(); + + // Send sync + javax.ws.rs.client.Client client = ClientBuilder.newClient(); + WebTarget target = client + .target(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", + config.getServer(), + config.getPort(), + userId)); + + Response response = target.request().post(Entity.entity(sync, "application/xml")); + + Sync returnSync = response.readEntity(Sync.class); + if (returnSync.getMessages().size() != 0) { + System.out.println("Message ID: " + returnSync.getMessages().get(0).getMetadata().getMessageId()); + } + + for (int i = 0; i < returnSync.getMessages().size(); i++) { + + // Print sync XML to console + JAXBContext jc2; + try { + jc2 = JAXBContext.newInstance("envoy.schema"); + Marshaller m = jc2.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.marshal(returnSync, System.out); + } catch (JAXBException e) { + e.printStackTrace(); + } + + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.SENT) { + // Update Local Messages with State WAITING (add Message ID and change State to + // SENT) + for (int j = 0; j < sync.getMessages().size(); j++) { + if (j == i) { + sync.getMessages() + .get(j) + .getMetadata() + .setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId()); + sync.getMessages() + .get(j) + .getMetadata() + .setState(returnSync.getMessages().get(j).getMetadata().getState()); + } + + } + + } + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getSender() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { + // these are the unread Messages from the server + unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); + + } + + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getSender() == 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { + // Update Messages in localDB to state RECEIVED + for (int j = 0; j < localDB.getChats().size(); j++) { + if (localDB.getChats().get(j).getRecipient().getID() == returnSync.getMessages() + .get(i) + .getMetadata() + .getRecipient()) { + for (int k = 0; k < localDB.getChats().get(j).getModel().getSize(); k++) { + if (localDB.getChats() + .get(j) + .getModel() + .get(k) + .getMetadata() + .getMessageId() == returnSync.getMessages().get(i).getMetadata().getMessageId()) { + // Update Message in LocalDB + localDB.getChats() + .get(j) + .getModel() + .get(k) + .getMetadata() + .setState(returnSync.getMessages().get(j).getMetadata().getState()); + } + } + } + } + + } + + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) { + // Update local Messages to state READ + System.out + .println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + + "was initialized to be set to READ in localDB."); + for (int j = 0; j < localDB.getChats().size(); j++) { + if (localDB.getChats().get(j).getRecipient().getID() == returnSync.getMessages() + .get(i) + .getMetadata() + .getRecipient()) { + System.out.println( + "Chat with: " + localDB.getChats().get(j).getRecipient().getID() + "was selected."); + for (int k = 0; k < localDB.getChats().get(j).getModel().getSize(); k++) { + if (localDB.getChats() + .get(j) + .getModel() + .get(k) + .getMetadata() + .getMessageId() == returnSync.getMessages().get(i).getMetadata().getMessageId()) { + System.out.println("Message with ID: " + + localDB.getChats().get(j).getModel().get(k).getMetadata().getMessageId() + + "was selected."); + localDB.getChats() + .get(j) + .getModel() + .get(k) + .getMetadata() + .setState(returnSync.getMessages().get(i).getMetadata().getState()); + System.out.println("Message State is now: " + localDB.getChats() + .get(j) + .getModel() + .get(k) + .getMetadata() + .getState() + .toString()); + } + } + } + } + + } + } + + // Updating UserStatus of all Users in LocalDB + for (int j = 0; j < returnSync.getUsers().size(); j++) { + for (int k = 0; k < localDB.getChats().size(); k++) { + if (localDB.getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) { + + localDB.getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus()); + System.out.println(localDB.getChats().get(k).getRecipient().getStatus().toString()); + } + } + } + + System.out.println("Response code: " + response.getStatus()); + + response.close(); + client.close(); + sync.getMessages().clear(); + sync.getUsers().clear(); + + }).start(); + System.out.println(sync.getMessages().size()); + } /** - * @return the sender object that represents this client + * Adds a message to the "sync" Sync object. + * + * @param message + * @since Envoy v0.1-alpha + */ + public void addMessageToSync(Message message) { sync.getMessages().add(message); } + + /** + * Adds a user to the "sync" Sync object. + * + * @param user + * @since Envoy v0.1-alpha + */ + public void addUserToSync(User user) { sync.getUsers().add(user); } + + /** + * Adds the unread Messages returned from the server in the latest sync to the + * right chats in the LocalDB. + * + * @param localDB + * @since Envoy v0.1-alpha + */ + public void addUnreadMessagesToLocalDB(LocalDB localDB) { + Sync unreadMessages = unreadMessagesSync; + for (int i = 0; i < unreadMessages.getMessages().size(); i++) + for (int j = 0; j < localDB.getChats().size(); j++) + if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessages() + .get(i) + .getMetadata() + .getSender()) { + localDB.getChats().get(j).appendMessage(unreadMessages.getMessages().get(i)); + } + } + + /** + * Gets all Messages with state SENT from the LocalDB and adds them to the + * "sync" Sync object. + * + * @param localDB + * @since Envoy v0.1-alpha + */ + public void getSentStateMessagesFromLocalDB(LocalDB localDB) { + for (int i = 0; i < localDB.getChats().size(); i++) { + for (int j = 0; j < localDB.getChats().get(i).getModel().getSize(); j++) { + if (localDB.getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.SENT) { + addMessageToSync(localDB.getChats().get(i).getModel().get(j)); + } + } + } + } + + /** + * Changes all Messages with State RECEIVED of a specific chat to State READ. + *
+ * Adds these Messages to the "readMessages" Sync object. + * + * @param currentChat + * @since Envoy v0.1-alpha + */ + public void setMessagesToRead(Chat currentChat) { + for (int j = 0; j < currentChat.getModel().getSize(); j++) { + if (currentChat.getModel().get(j).getMetadata().getRecipient() != currentChat.getRecipient().getID()) { + if (currentChat.getModel().get(j).getMetadata().getState() == MessageState.RECEIVED) { + currentChat.getModel().get(j).getMetadata().setState(MessageState.READ); + readMessages.getMessages().add(currentChat.getModel().get(j)); + } + } + } + } + + /** + * Adds a Message with State WAITING to a specific chat in the LocalDB. + * + * @param message + * @param currentChat + * @since Envoy v0.1-alpha + */ + public void addWaitingMessageToLocalDB(Message message, Chat currentChat) { currentChat.appendMessage(message); } + + /** + * Adds all Messages with State WAITING from the LocalDB to the Sync. + * + * @param localDB + * @since Envoy v0.1-alpha + */ + public void addWaitingMessagesToSync(LocalDB localDB) { + for (int i = 0; i < localDB.getChats().size(); i++) { + for (int j = 0; j < localDB.getChats().get(i).getModel().getSize(); j++) { + if (localDB.getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.WAITING) { + // addMessageToSync(localDB.getChats().get(i).getModel().get(j)); + System.out.println("Got Waiting Message"); + sync.getMessages().add(0, localDB.getChats().get(i).getModel().get(j)); + } + } + } + } + + /** + * @return the sender object that represents this client. * @since Envoy v0.1-alpha */ public User getSender() { return sender; } + /** + * @return the current recipient of the current chat. + * @since Envoy v0.1-alpha + */ public User getRecipient() { return recipient; } + /** + * Sets the recipient. + * + * @param recipient + * @since Envoy v0.1-alpha + */ public void setRecipient(User recipient) { this.recipient = recipient; } + /** + * @return boolean weather the recipient is currently set. + * @since Envoy v0.1-alpha + */ public boolean hasRecipient() { return recipient != null; } + + /** + * Clears the "unreadMessagesSync" Sync object. + * + * @since Envoy v0.1-alpha + */ + public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 5f79b13..4ac1a6c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -27,9 +27,9 @@ import envoy.client.Chat; import envoy.client.Client; import envoy.client.LocalDB; import envoy.schema.Message; -import envoy.schema.Messages; +import envoy.schema.Sync; import envoy.schema.User; -import envoy.schema.Users; + /** * Project: envoy-client
@@ -147,18 +147,17 @@ public class ChatWindow extends JFrame { postButton.addActionListener((evt) -> { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); - return; + JOptionPane.showMessageDialog(this, + "Please select a recipient!", + "Cannot send message", + JOptionPane.INFORMATION_MESSAGE); } if (!messageEnterTextfield.getText().isEmpty()) try { // Create and send message object final Message message = client.createMessage(messageEnterTextfield.getText()); - client.sendMessage(message); - - // Append message object to chat - currentChat.appendMessage(message); + client.addWaitingMessageToLocalDB(message, currentChat); messageList.setModel(currentChat.getModel()); // Clear text field @@ -200,16 +199,23 @@ public class ChatWindow extends JFrame { final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); + currentChat = localDB.getChats() + .stream() + .filter(chat -> chat.getRecipient().getID() == user.getID()) + .findFirst() + .get(); client.setRecipient(user); textPane.setText(currentChat.getRecipient().getName()); + messageList.setModel(currentChat.getModel()); contentPane.revalidate(); } }); - + + + userList.setSelectionForeground(new Color(255, 255, 255)); userList.setSelectionBackground(new Color(102, 0, 153)); userList.setForeground(new Color(255, 255, 255)); @@ -227,6 +233,7 @@ public class ChatWindow extends JFrame { contentPane.add(userList, gbc_userList); contentPane.revalidate(); + loadUsersAndChats(); startReceiverThread(5000); @@ -239,9 +246,9 @@ public class ChatWindow extends JFrame { */ private void loadUsersAndChats() { new Thread(() -> { - Users users = client.getUsersListXml(); + Sync users = client.getUsersListXml(); DefaultListModel userListModel = new DefaultListModel<>(); - users.getUser().forEach(user -> { + users.getUsers().forEach(user -> { userListModel.addElement(user); // Check if user exists in local DB @@ -253,18 +260,34 @@ public class ChatWindow extends JFrame { } /** - * Checks for new messages and adds them to the chat list. + * For detailed information see Javadoc of corresponding methods. * * @param timeout the amount of time that passes between two requests sent to * the server + * @since Envoy v0.1-alpha */ private void startReceiverThread(int timeout) { new Timer(timeout, (evt) -> { - Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); - for (int i = 0; i < unreadMessages.getMessage().size(); i++) - for (int j = 0; j < localDB.getChats().size(); j++) - if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) - localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); - }).start(); + if(currentChat != null) { + client.setMessagesToRead(currentChat); + } + client.sendSync(client.getSender().getID(), localDB); + client.addUnreadMessagesToLocalDB(localDB); + client.clearUnreadMessagesSync(); + + for (int i = 0; i < userList.getModel().getSize(); i++) { + for (int j = 0; j < localDB.getChats().size(); j++) { + if(userList.getModel().getElementAt(i).getID() == localDB.getChats().get(j).getRecipient().getID()) { + userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); + } + } + + } + + contentPane.revalidate(); + contentPane.repaint(); + userList.revalidate(); + userList.repaint(); + }).start(); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 4490b69..7afdec3 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -18,6 +18,7 @@ import envoy.schema.Message; * Created: 19 Oct 2019
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy v0.1-alpha */ public class MessageListRenderer extends JLabel implements ListCellRenderer { @@ -38,14 +39,16 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer

%s

%s", + "

%s

%s :%s", date, - text)); + text, + state)); return this; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index c0c13ba..40bb2ad 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -7,6 +7,7 @@ import javax.swing.JList; import javax.swing.ListCellRenderer; import envoy.schema.User; +import envoy.schema.User.UserStatus; /** * Defines how the {@code UserList} is displayed. @@ -16,6 +17,7 @@ import envoy.schema.User; * Created: 12 Oct 2019
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy v0.1-alpha */ public class UserListRenderer extends JLabel implements ListCellRenderer { @@ -36,8 +38,27 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { // Enable background rendering setOpaque(true); - setText(value.getName()); - setFont(list.getFont()); + + final String name = value.getName(); + final UserStatus status = value.getStatus(); + + switch (status) { + case ONLINE: + setText(String.format( + "

%s

%s", + status, + name)); + break; + + case OFFLINE: + setText(String.format( + "

%s

%s", + status, + name)); + break; + } + + return this; } From 2d3d595164874a42a21acf8cf3b492aa67761fcc Mon Sep 17 00:00:00 2001 From: delvh Date: Tue, 5 Nov 2019 13:30:23 +0100 Subject: [PATCH 049/474] Added KeyListeners for sending the message and an automatic line break --- src/main/java/envoy/client/ui/ChatWindow.java | 140 ++++++++---------- .../java/envoy/client/ui/SettingsScreen.java | 8 +- 2 files changed, 62 insertions(+), 86 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index f6625b5..90bb87d 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -6,8 +6,7 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; -import java.awt.event.InputMethodEvent; -import java.awt.event.InputMethodListener; +import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; @@ -56,7 +55,7 @@ public class ChatWindow extends JFrame { private JList userList = new JList<>(); private Chat currentChat; - private String messageText; + private JTextArea messageEnterTextArea; public ChatWindow(Client client, LocalDB localDB) { this.client = client; @@ -118,38 +117,29 @@ public class ChatWindow extends JFrame { contentPane.add(scrollPane, gbc_scrollPane); // Message enter field - JTextArea messageEnterTextfield = new JTextArea(); - // checks for changed Message - messageEnterTextfield.addInputMethodListener(new InputMethodListener() { + messageEnterTextArea = new JTextArea(); + messageEnterTextArea.addKeyListener(new KeyAdapter() { - public void caretPositionChanged(InputMethodEvent arg0) {} + @Override + public void keyReleased(KeyEvent e) { + + if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) + || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + postMessage(client, messageList); - public void inputMethodTextChanged(InputMethodEvent arg0) { - String message = messageEnterTextfield.getText(); - int messageSize = message.length(); - int lineSize = 45; - String[] tempString = message.split(System.getProperty("line.separator")); - int currentLineAmount = tempString.length; - int wantedLineAmount = Math.floorDiv(messageSize, lineSize); - if (currentLineAmount != wantedLineAmount) { - if (Math.abs(messageText.length() - messageSize) == 1 - && currentLineAmount == wantedLineAmount - 1) {// Check for "normal" Keystroke/Backspace - messageEnterTextfield.setText(transformLastSpace(message, wantedLineAmount, lineSize)); - } - } else {// That's the case if a group of chars was a)inserted or b)deleted - // TODO } - messageText = message; - } + } }); - messageEnterTextfield.setCaretColor(new Color(255, 255, 255)); - messageEnterTextfield.setForeground(new Color(255, 255, 255)); - messageEnterTextfield.setBackground(new Color(51, 51, 51)); - messageEnterTextfield.setLineWrap(true); - messageEnterTextfield.setBorder(null); - messageEnterTextfield.setFont(new Font("Arial", Font.PLAIN, 17)); - messageEnterTextfield.setBorder(new EmptyBorder(5, 5, 5, 5)); + // checks for changed Message + messageEnterTextArea.setWrapStyleWord(true); + messageEnterTextArea.setCaretColor(new Color(255, 255, 255)); + messageEnterTextArea.setForeground(new Color(255, 255, 255)); + messageEnterTextArea.setBackground(new Color(51, 51, 51)); + messageEnterTextArea.setLineWrap(true); + messageEnterTextArea.setBorder(null); + messageEnterTextArea.setFont(new Font("Arial", Font.PLAIN, 17)); + messageEnterTextArea.setBorder(new EmptyBorder(5, 5, 5, 5)); GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; @@ -158,13 +148,10 @@ public class ChatWindow extends JFrame { gbc_messageEnterTextfield.insets = new Insets(10, 10, 10, 10); - contentPane.add(messageEnterTextfield, gbc_messageEnterTextfield); + contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); // Post Button JButton postButton = new JButton("Post"); - if (SettingsScreen.isEnterToSend() == true) { postButton.setMnemonic(KeyEvent.VK_ENTER); } - // TODO: Other option to send only on "ctrl"+"enter" needs to be implemented. - // TODO: Difficult. Also above statement doesn't work! postButton.setForeground(new Color(255, 255, 255)); postButton.setBackground(new Color(102, 51, 153)); postButton.setBorderPainted(false); @@ -177,36 +164,7 @@ public class ChatWindow extends JFrame { gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); - postButton.addActionListener((evt) -> { - if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, - "Please select a recipient!", - "Cannot send message", - JOptionPane.INFORMATION_MESSAGE); - return; - } - - if (!messageEnterTextfield.getText().isEmpty()) try { - - // Create and send message object - final Message message = client.createMessage(messageEnterTextfield.getText()); - client.sendMessage(message); - - // Append message object to chat - currentChat.appendMessage(message); - messageList.setModel(currentChat.getModel()); - - // Clear text field - messageEnterTextfield.setText(""); - contentPane.revalidate(); - } catch (Exception e) { - JOptionPane.showMessageDialog(this, - "An exception occured while sending a message. See the log for more details.", - "Exception occured", - JOptionPane.ERROR_MESSAGE); - e.printStackTrace(); - } - }); + postButton.addActionListener((evt) -> { postMessage(client, messageList); }); contentPane.add(postButton, gbc_moveSelectionPostButton); @@ -229,7 +187,7 @@ public class ChatWindow extends JFrame { SettingsScreen.open(localDB.getUser().getName()); } catch (Exception e) { SettingsScreen.open(); - System.err.println("An Error occured while opening the Settings screen"); + System.err.println("An Error occured while opening the Settings screen: " + e); e.printStackTrace(); } }); @@ -243,10 +201,9 @@ public class ChatWindow extends JFrame { textPane.setFont(new Font("Arial", Font.PLAIN, 20)); GridBagConstraints gbc_partnerName = new GridBagConstraints(); - gbc_partnerName.fill = GridBagConstraints.HORIZONTAL; - gbc_partnerName.gridwidth = 2; - gbc_partnerName.gridx = 1; - gbc_partnerName.gridy = 0; + gbc_partnerName.fill = GridBagConstraints.HORIZONTAL; + gbc_partnerName.gridx = 1; + gbc_partnerName.gridy = 0; gbc_partnerName.insets = new Insets(0, 10, 0, 10); contentPane.add(textPane, gbc_partnerName); @@ -298,22 +255,41 @@ public class ChatWindow extends JFrame { } /** - * takes care of too long or not needed lines in the message. + * Posts a {@link Message}. Is used only twice: Once for clicking on the {@code postButton}
+ * and once for pressing the KeyStroke(s) to send a message ( (ctrl+)enter) * - * @param message the message that is currently written in the textfield - * @param wantedLine the line at which we currently are positioned - * @param lineSize the amount of chars per line - * @return the transformed message + * @param client the client who wants to send a {@link Message} + * @param messageList the chat in which this {@link Message} belongs * @since Envoy v0.1-alpha */ - private String transformLastSpace(String message, int wantedLine, int lineSize) { - int index = wantedLine * lineSize; - int lastSpace = message.lastIndexOf(" ", index); - if (index - lastSpace > lineSize) {// Fall Wort länger als Zeile - return message.substring(0, index) + System.getProperty("line.separator") + message.substring(index); - } else { - return message.substring(0, lastSpace - 1) + System.getProperty("line.separator") - + message.substring(lastSpace + 1); + private void postMessage(Client client, JList messageList) { + if (!client.hasRecipient()) { + JOptionPane.showMessageDialog(this, + "Please select a recipient!", + "Cannot send message", + JOptionPane.INFORMATION_MESSAGE); + return; + } + + if (!messageEnterTextArea.getText().isEmpty()) try { + + // Create and send message object + final Message message = client.createMessage(messageEnterTextArea.getText()); + client.sendMessage(message); + + // Append message object to chat + currentChat.appendMessage(message); + messageList.setModel(currentChat.getModel()); + + // Clear text field + messageEnterTextArea.setText(""); + contentPane.revalidate(); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "An exception occured while sending a message. See the log for more details.", + "Exception occured", + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); } } diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index 7a4edab..8761160 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -20,7 +20,7 @@ public class SettingsScreen extends JDialog { private static final long serialVersionUID = -4476913491263077107L; private final JPanel contentPanel = new JPanel(); - public static boolean EnterToSend = true; + public static boolean enterToSend = true; // TODO: Add a JPanel with all the Information necessary: // change (Picture,Username, Email, Password) and toggle(light/dark mode, @@ -139,10 +139,10 @@ public class SettingsScreen extends JDialog { } /** - * @return true if Enter should be used to send a message + * @return true if Enter should be used to send a message instead of ctrl+enter * @since Envoy v0.1-alpha */ - public static boolean isEnterToSend() { return EnterToSend; } + public static boolean isEnterToSend() { return enterToSend; } /** * @param enterToSend
@@ -151,6 +151,6 @@ public class SettingsScreen extends JDialog { * buttonpress "enter" or "ctrl"+"enter" * @since Envoy v0.1-alpha */ - public static void setEnterToSend(boolean enterToSend) { EnterToSend = enterToSend; } + public static void setEnterToSend(boolean enterForSend) { enterToSend = enterForSend; } // TODO: Should be changed to private, but later to avoid warnings } From 67f9f5133f2579b2fc1480fa67cd5d571474a11e Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 9 Nov 2019 09:38:10 +0100 Subject: [PATCH 050/474] Extracted updateUserStates method, fixed localDB initialization --- src/main/java/envoy/client/Config.java | 1 + src/main/java/envoy/client/ui/ChatWindow.java | 18 ++++++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 1d107ca..0da3cf1 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -53,6 +53,7 @@ public class Config { case "-db": localDB = new File(args[++i]); } + if (localDB == null) localDB = new File(".\\localDB"); } /** diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 4ac1a6c..490308d 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -275,19 +275,17 @@ public class ChatWindow extends JFrame { client.addUnreadMessagesToLocalDB(localDB); client.clearUnreadMessagesSync(); - for (int i = 0; i < userList.getModel().getSize(); i++) { - for (int j = 0; j < localDB.getChats().size(); j++) { - if(userList.getModel().getElementAt(i).getID() == localDB.getChats().get(j).getRecipient().getID()) { - userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); - } - } - - } + updateUserStates(); contentPane.revalidate(); contentPane.repaint(); - userList.revalidate(); - userList.repaint(); }).start(); } + + private void updateUserStates() { + for (int i = 0; i < userList.getModel().getSize(); i++) + for (int j = 0; j < localDB.getChats().size(); j++) + if (userList.getModel().getElementAt(i).getID() == localDB.getChats().get(j).getRecipient().getID()) + userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); + } } \ No newline at end of file From 59fc855364a6c349e348a08cf567aca7a3b843ce Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 9 Nov 2019 09:52:27 +0100 Subject: [PATCH 051/474] minor changes in ChatWindow and SettingsScreen --- src/main/java/envoy/client/ui/ChatWindow.java | 5 +++-- .../java/envoy/client/ui/SettingsScreen.java | 18 +++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 90bb87d..1e43245 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -255,10 +255,11 @@ public class ChatWindow extends JFrame { } /** - * Posts a {@link Message}. Is used only twice: Once for clicking on the {@code postButton}
+ * Posts a {@link Message}. Is used only twice: Once for clicking on the + * {@code postButton}
* and once for pressing the KeyStroke(s) to send a message ( (ctrl+)enter) * - * @param client the client who wants to send a {@link Message} + * @param client the client who wants to send a {@link Message} * @param messageList the chat in which this {@link Message} belongs * @since Envoy v0.1-alpha */ diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index 8761160..7d5de28 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -33,25 +33,25 @@ public class SettingsScreen extends JDialog { * * @since Envoy v0.1-alpha */ - public static void open() { - SettingsScreen dialog = new SettingsScreen(); - dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - dialog.setVisible(true); - } + public static void open() { open(new SettingsScreen()); } /** * Opens the Settings screen.
- * Use preferreably since everyone is already initialised.
+ * Use preferably since everyone is already initialised.
* It personalises the screen more. * - * @param Username The name of the User + * @param username The name of the User * @param Email The Email that is associated with that Account * @since Envoy v0.1-alpha */ - public static void open(String Username) {// , String Email) {AUSKLAMMERN, WENN ANMELDUNG PER + public static void open(String username) {// , String Email) {AUSKLAMMERN, WENN ANMELDUNG PER // EMAIL IMPLEMENTIERT IST! - SettingsScreen dialog = new SettingsScreen(Username); + open(new SettingsScreen(username)); + } + + public static void open(SettingsScreen dialog) { dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setModal(true); dialog.setVisible(true); } From 9c88e14d07536d4f17d3bd38d745b9cafb46ae1e Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 9 Nov 2019 10:04:58 +0100 Subject: [PATCH 052/474] Update Client.java --- src/main/java/envoy/client/Client.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 120d7dc..a0878e2 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -172,7 +172,7 @@ public class Client { public User getSender() { return sender; } /** - * @return the recipient of a message. + * @return the recipient of a message * @since Envoy v0.1-alpha */ public User getRecipient() { return recipient; } @@ -188,4 +188,4 @@ public class Client { * @since Envoy v0.1-alpha */ public boolean hasRecipient() { return recipient != null; } -} \ No newline at end of file +} From 9c0be9cd9a331763fd06ca24f3e9eb0f16e71bcc Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 9 Nov 2019 10:23:00 +0100 Subject: [PATCH 053/474] Improved ChatWindow according to CyB3RC0nN0Rs Feedback --- src/main/java/envoy/client/ui/ChatWindow.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 1e43245..f8c2fcf 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -131,7 +131,7 @@ public class ChatWindow extends JFrame { } }); - // checks for changed Message + // Checks for changed Message messageEnterTextArea.setWrapStyleWord(true); messageEnterTextArea.setCaretColor(new Color(255, 255, 255)); messageEnterTextArea.setForeground(new Color(255, 255, 255)); @@ -187,7 +187,7 @@ public class ChatWindow extends JFrame { SettingsScreen.open(localDB.getUser().getName()); } catch (Exception e) { SettingsScreen.open(); - System.err.println("An Error occured while opening the Settings screen: " + e); + System.err.println("An error occured while opening the settings screen: " + e); e.printStackTrace(); } }); From 52f2f8e1c22104c660993a12e23404f60b425950 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 9 Nov 2019 13:25:18 +0100 Subject: [PATCH 054/474] Revised structure --- src/main/java/envoy/client/Client.java | 397 +++--------------- src/main/java/envoy/client/LocalDB.java | 302 ++++++++++++- src/main/java/envoy/client/ui/ChatWindow.java | 42 +- 3 files changed, 377 insertions(+), 364 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index b755c4a..ed2ff22 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -31,51 +31,30 @@ import envoy.schema.User; public class Client { private ObjectFactory objectFactory = new ObjectFactory(); - private DatatypeFactory datatypeFactory; private Config config; private User sender, recipient; - private Sync unreadMessagesSync = objectFactory.createSync(); - public Sync sync = objectFactory.createSync(); - public Sync readMessages = objectFactory.createSync(); - public Client(Config config, String username) { - this.config = config; - try { - datatypeFactory = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException e) { - e.printStackTrace(); - } - sender = getUser(username); + this.config = config; + sender = getUser(username); System.out.println("ID: " + sender.getID()); } - /** - * Creates a {@link Message} object serializable to XML. - * - * @param textContent The content (text) of the message - * @return prepared {@link Message} object - */ - public Message createMessage(String textContent) { - Message.Metadata metaData = objectFactory.createMessageMetadata(); - metaData.setSender(sender.getID()); - metaData.setRecipient(recipient.getID()); - metaData.setState(MessageState.WAITING); - metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); + private R post(String uri, T body, Class responseBodyClass) { + javax.ws.rs.client.Client client = ClientBuilder.newClient(); + WebTarget target = client.target(uri); - Message.Content content = objectFactory.createMessageContent(); - content.setType("text"); - content.setText(textContent); + Response response = target.request().post(Entity.entity(body, "application/xml")); + R responseBody = response.readEntity(responseBodyClass); + response.close(); + client.close(); - Message message = objectFactory.createMessage(); - message.setMetadata(metaData); - message.getContent().add(content); - - return message; + return responseBody; } - + /** * Returns a {@link Sync} with all users on the server. + * * @return Sync - List of all users on the server. * @since Envoy v0.1-alpha */ @@ -85,14 +64,11 @@ public class Client { user.setID(-1); sendSync.getUsers().add(user); - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client.target(String - .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0)); - - Response response = target.request().post(Entity.entity(sendSync, "application/xml")); - Sync returnSendSync = response.readEntity(Sync.class); - response.close(); - client.close(); + Sync returnSendSync = post( + String + .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + sendSync, + Sync.class); return returnSendSync; } @@ -110,321 +86,74 @@ public class Client { user.setName(name); senderSync.getUsers().add(user); - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client.target(String - .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0)); + Sync returnSenderSync = post( + String + .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + senderSync, + Sync.class); + + User returnSender = objectFactory.createUser(); - Response response = target.request().post(Entity.entity(senderSync, "application/xml")); - User returnSender = objectFactory.createUser(); - Sync returnSenderSync = response.readEntity(Sync.class); if (returnSenderSync.getUsers().size() == 1) { returnSender = returnSenderSync.getUsers().get(0); } else { System.out.println("ERROR exiting..."); } - response.close(); - client.close(); + return returnSender; } /** * Sends the "sync" Sync Object to the server and gets a "returnSync" Sync * Object as response.
- * It is also used to get the own sender at the start of the client - * (Client sends "sync" Sync Object with single user in it(name: the name entered at login, id: 0, UserStatus:null))
- * and to get a complete list of all users saved on the server. - * (Client sends "sync" Sync Object with single user in it(name: "" (empty), id: -1, UserStatus:null))
+ * It is also used to get the own sender at the start of the client + * (Client sends "sync" Sync Object with single user in it(name: the name + * entered at login, id: 0, UserStatus:null))
+ * and to get a complete list of all users saved on the server. + * (Client sends "sync" Sync Object with single user in it(name: "" (empty), id: + * -1, UserStatus:null))
* This method also processes the response Sync Object.
* It sorts its users and messages by specific variables and does certain things * with them.
*
* Messages:
- * -State SENT: Update Local message(s) with State WAITING (add Message ID and - * change State to SENT). (server sends these informations to the client if - * message(s) with State WAITING were successfully sent to the server)
- * -State RECEIVED, SenderID != 0: Adds the unread Messages returned from the - * server in the latest sync to the "unreadMessagesSync" Sync Object.
- * -State RECEIVED, SenderID == 0: Update message(s) in localDB to state RECEIVED. - * (server sends these informations to the client if the other client received - * the message(s).)
- * -State READ: Update message(s) in the LocalDB to state READ. (server sends these informations to the client if the other client read - * the message(s).)
+ * -State SENT: Update Local message(s) with State WAITING (add Message ID and + * change State to SENT). (server sends these informations to the client if + * message(s) with State WAITING were successfully sent to the server)
+ * -State RECEIVED, SenderID != 0: Adds the unread Messages returned from the + * server in the latest sync to the "unreadMessagesSync" Sync Object.
+ * -State RECEIVED, SenderID == 0: Update message(s) in localDB to state + * RECEIVED. + * (server sends these informations to the client if the other client received + * the message(s).)
+ * -State READ: Update message(s) in the LocalDB to state READ. (server sends + * these informations to the client if the other client read + * the message(s).)
*
* Users:
- * Updating UserStatus of all users in LocalDB. (Server sends all users with their updated UserStatus to the client.)
+ * Updating UserStatus of all users in LocalDB. (Server sends all users with + * their updated UserStatus to the client.)
* * @param userId - * @param localDB * @since Envoy v0.1-alpha */ - public void sendSync(long userId, LocalDB localDB) { - new Thread(() -> { - // Print sync XML to console - JAXBContext jc; - try { - jc = JAXBContext.newInstance("envoy.schema"); - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - m.marshal(sync, System.out); - } catch (JAXBException e) { - e.printStackTrace(); - } - addWaitingMessagesToSync(localDB); - - getSentStateMessagesFromLocalDB(localDB); - for (int i = 0; i < readMessages.getMessages().size(); i++) { - sync.getMessages().add(readMessages.getMessages().get(i)); - } - readMessages.getMessages().clear(); - - // Send sync - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client - .target(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", - config.getServer(), - config.getPort(), - userId)); - - Response response = target.request().post(Entity.entity(sync, "application/xml")); - - Sync returnSync = response.readEntity(Sync.class); - if (returnSync.getMessages().size() != 0) { - System.out.println("Message ID: " + returnSync.getMessages().get(0).getMetadata().getMessageId()); - } - - for (int i = 0; i < returnSync.getMessages().size(); i++) { - - // Print sync XML to console - JAXBContext jc2; - try { - jc2 = JAXBContext.newInstance("envoy.schema"); - Marshaller m = jc2.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - m.marshal(returnSync, System.out); - } catch (JAXBException e) { - e.printStackTrace(); - } - - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.SENT) { - // Update Local Messages with State WAITING (add Message ID and change State to - // SENT) - for (int j = 0; j < sync.getMessages().size(); j++) { - if (j == i) { - sync.getMessages() - .get(j) - .getMetadata() - .setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId()); - sync.getMessages() - .get(j) - .getMetadata() - .setState(returnSync.getMessages().get(j).getMetadata().getState()); - } - - } - - } - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 - && returnSync.getMessages().get(i).getMetadata().getSender() != 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { - // these are the unread Messages from the server - unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); - - } - - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 - && returnSync.getMessages().get(i).getMetadata().getSender() == 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { - // Update Messages in localDB to state RECEIVED - for (int j = 0; j < localDB.getChats().size(); j++) { - if (localDB.getChats().get(j).getRecipient().getID() == returnSync.getMessages() - .get(i) - .getMetadata() - .getRecipient()) { - for (int k = 0; k < localDB.getChats().get(j).getModel().getSize(); k++) { - if (localDB.getChats() - .get(j) - .getModel() - .get(k) - .getMetadata() - .getMessageId() == returnSync.getMessages().get(i).getMetadata().getMessageId()) { - // Update Message in LocalDB - localDB.getChats() - .get(j) - .getModel() - .get(k) - .getMetadata() - .setState(returnSync.getMessages().get(j).getMetadata().getState()); - } - } - } - } - - } - - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) { - // Update local Messages to state READ - System.out - .println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() - + "was initialized to be set to READ in localDB."); - for (int j = 0; j < localDB.getChats().size(); j++) { - if (localDB.getChats().get(j).getRecipient().getID() == returnSync.getMessages() - .get(i) - .getMetadata() - .getRecipient()) { - System.out.println( - "Chat with: " + localDB.getChats().get(j).getRecipient().getID() + "was selected."); - for (int k = 0; k < localDB.getChats().get(j).getModel().getSize(); k++) { - if (localDB.getChats() - .get(j) - .getModel() - .get(k) - .getMetadata() - .getMessageId() == returnSync.getMessages().get(i).getMetadata().getMessageId()) { - System.out.println("Message with ID: " - + localDB.getChats().get(j).getModel().get(k).getMetadata().getMessageId() - + "was selected."); - localDB.getChats() - .get(j) - .getModel() - .get(k) - .getMetadata() - .setState(returnSync.getMessages().get(i).getMetadata().getState()); - System.out.println("Message State is now: " + localDB.getChats() - .get(j) - .getModel() - .get(k) - .getMetadata() - .getState() - .toString()); - } - } - } - } - - } - } - - // Updating UserStatus of all Users in LocalDB - for (int j = 0; j < returnSync.getUsers().size(); j++) { - for (int k = 0; k < localDB.getChats().size(); k++) { - if (localDB.getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) { - - localDB.getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus()); - System.out.println(localDB.getChats().get(k).getRecipient().getStatus().toString()); - } - } - } - - System.out.println("Response code: " + response.getStatus()); - - response.close(); - client.close(); - sync.getMessages().clear(); - sync.getUsers().clear(); - - }).start(); - System.out.println(sync.getMessages().size()); - - } - - /** - * Adds a message to the "sync" Sync object. - * - * @param message - * @since Envoy v0.1-alpha - */ - public void addMessageToSync(Message message) { sync.getMessages().add(message); } - - /** - * Adds a user to the "sync" Sync object. - * - * @param user - * @since Envoy v0.1-alpha - */ - public void addUserToSync(User user) { sync.getUsers().add(user); } - - /** - * Adds the unread Messages returned from the server in the latest sync to the - * right chats in the LocalDB. - * - * @param localDB - * @since Envoy v0.1-alpha - */ - public void addUnreadMessagesToLocalDB(LocalDB localDB) { - Sync unreadMessages = unreadMessagesSync; - for (int i = 0; i < unreadMessages.getMessages().size(); i++) - for (int j = 0; j < localDB.getChats().size(); j++) - if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessages() - .get(i) - .getMetadata() - .getSender()) { - localDB.getChats().get(j).appendMessage(unreadMessages.getMessages().get(i)); - } - } - - /** - * Gets all Messages with state SENT from the LocalDB and adds them to the - * "sync" Sync object. - * - * @param localDB - * @since Envoy v0.1-alpha - */ - public void getSentStateMessagesFromLocalDB(LocalDB localDB) { - for (int i = 0; i < localDB.getChats().size(); i++) { - for (int j = 0; j < localDB.getChats().get(i).getModel().getSize(); j++) { - if (localDB.getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.SENT) { - addMessageToSync(localDB.getChats().get(i).getModel().get(j)); - } - } + public Sync sendSync(long userId, Sync sync) { + // Print sync XML to console + JAXBContext jc; + try { + jc = JAXBContext.newInstance("envoy.schema"); + Marshaller m = jc.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.marshal(sync, System.out); + } catch (JAXBException e) { + e.printStackTrace(); } - } - /** - * Changes all Messages with State RECEIVED of a specific chat to State READ. - *
- * Adds these Messages to the "readMessages" Sync object. - * - * @param currentChat - * @since Envoy v0.1-alpha - */ - public void setMessagesToRead(Chat currentChat) { - for (int j = 0; j < currentChat.getModel().getSize(); j++) { - if (currentChat.getModel().get(j).getMetadata().getRecipient() != currentChat.getRecipient().getID()) { - if (currentChat.getModel().get(j).getMetadata().getState() == MessageState.RECEIVED) { - currentChat.getModel().get(j).getMetadata().setState(MessageState.READ); - readMessages.getMessages().add(currentChat.getModel().get(j)); - } - } - } - } - - /** - * Adds a Message with State WAITING to a specific chat in the LocalDB. - * - * @param message - * @param currentChat - * @since Envoy v0.1-alpha - */ - public void addWaitingMessageToLocalDB(Message message, Chat currentChat) { currentChat.appendMessage(message); } - - /** - * Adds all Messages with State WAITING from the LocalDB to the Sync. - * - * @param localDB - * @since Envoy v0.1-alpha - */ - public void addWaitingMessagesToSync(LocalDB localDB) { - for (int i = 0; i < localDB.getChats().size(); i++) { - for (int j = 0; j < localDB.getChats().get(i).getModel().getSize(); j++) { - if (localDB.getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.WAITING) { - // addMessageToSync(localDB.getChats().get(i).getModel().get(j)); - System.out.println("Got Waiting Message"); - sync.getMessages().add(0, localDB.getChats().get(i).getModel().get(j)); - } - } - } + // Send sync + return post(String + .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), + sync, + Sync.class); } /** @@ -453,10 +182,4 @@ public class Client { */ public boolean hasRecipient() { return recipient != null; } - /** - * Clears the "unreadMessagesSync" Sync object. - * - * @since Envoy v0.1-alpha - */ - public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index d7b3409..e63fc72 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -6,11 +6,22 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.time.Instant; import java.util.ArrayList; import java.util.List; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; + import envoy.exception.EnvoyException; +import envoy.schema.Message; import envoy.schema.User; +import envoy.schema.Message.Metadata.MessageState; +import envoy.schema.ObjectFactory; +import envoy.schema.Sync; /** * Project: envoy-client
@@ -22,9 +33,11 @@ import envoy.schema.User; */ public class LocalDB { - private File localDB; - private User sender; - private List chats = new ArrayList<>(); + private File localDB; + private User sender; + private List chats = new ArrayList<>(); + private ObjectFactory objectFactory = new ObjectFactory(); + private DatatypeFactory datatypeFactory; /** * Constructs an empty local database. @@ -32,7 +45,14 @@ public class LocalDB { * @param sender the user that is logged in with this client * @since Envoy v0.1-alpha **/ - public LocalDB(User sender) { this.sender = sender; } + public LocalDB(User sender) { + this.sender = sender; + try { + datatypeFactory = DatatypeFactory.newInstance(); + } catch (DatatypeConfigurationException e) { + e.printStackTrace(); + } + } /** * Initializes the local database and fills it with values @@ -43,8 +63,8 @@ public class LocalDB { * @since Envoy v0.1-alpha **/ public void initializeDBFile(File localDBDir) throws EnvoyException { - if (localDBDir.exists() && !localDBDir.isDirectory()) - throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); + if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException( + String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); localDB = new File(localDBDir, sender.getID() + ".db"); if (localDB.exists()) loadFromLocalDB(); } @@ -87,6 +107,276 @@ public class LocalDB { } } + // TODO + /** + * Creates a {@link Message} object serializable to XML. + * + * @param textContent The content (text) of the message + * @return prepared {@link Message} object + */ + public Message createMessage(String textContent, User recipient) { + Message.Metadata metaData = objectFactory.createMessageMetadata(); + metaData.setSender(sender.getID()); + metaData.setRecipient(recipient.getID()); + metaData.setState(MessageState.WAITING); + metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); + + Message.Content content = objectFactory.createMessageContent(); + content.setType("text"); + content.setText(textContent); + + Message message = objectFactory.createMessage(); + message.setMetadata(metaData); + message.getContent().add(content); + + return message; + } + + private Sync unreadMessagesSync = objectFactory.createSync(); + public Sync sync = objectFactory.createSync(); + public Sync readMessages = objectFactory.createSync(); + + public Sync fillSync(long userId) { + + addWaitingMessagesToSync(); + + getSentStateMessagesFromLocalDB(); + for (int i = 0; i < readMessages.getMessages().size(); i++) { + sync.getMessages().add(readMessages.getMessages().get(i)); + } + readMessages.getMessages().clear(); + + + System.out.println(sync.getMessages().size()); + return sync; + } + + public void applySync (Sync returnSync) { + for (int i = 0; i < returnSync.getMessages().size(); i++) { + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.SENT) { + // Update Local Messages with State WAITING (add Message ID and change State to + // SENT) + for (int j = 0; j < sync.getMessages().size(); j++) { + if (j == i) { + sync.getMessages() + .get(j) + .getMetadata() + .setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId()); + sync.getMessages() + .get(j) + .getMetadata() + .setState(returnSync.getMessages().get(j).getMetadata().getState()); + } + + } + + } + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getSender() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { + // these are the unread Messages from the server + unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); + + } + + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getSender() == 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { + // Update Messages in localDB to state RECEIVED + for (int j = 0; j < getChats().size(); j++) { + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages() + .get(i) + .getMetadata() + .getRecipient()) { + for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { + if (getChats() + .get(j) + .getModel() + .get(k) + .getMetadata() + .getMessageId() == returnSync.getMessages().get(i).getMetadata().getMessageId()) { + // Update Message in LocalDB + getChats() + .get(j) + .getModel() + .get(k) + .getMetadata() + .setState(returnSync.getMessages().get(j).getMetadata().getState()); + } + } + } + } + + } + + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) { + // Update local Messages to state READ + System.out + .println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + + "was initialized to be set to READ in localDB."); + for (int j = 0; j < getChats().size(); j++) { + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages() + .get(i) + .getMetadata() + .getRecipient()) { + System.out.println( + "Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); + for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { + if (getChats() + .get(j) + .getModel() + .get(k) + .getMetadata() + .getMessageId() == returnSync.getMessages().get(i).getMetadata().getMessageId()) { + System.out.println("Message with ID: " + + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + + "was selected."); + getChats() + .get(j) + .getModel() + .get(k) + .getMetadata() + .setState(returnSync.getMessages().get(i).getMetadata().getState()); + System.out.println("Message State is now: " + getChats() + .get(j) + .getModel() + .get(k) + .getMetadata() + .getState() + .toString()); + } + } + } + } + + } + } + + // Updating UserStatus of all Users in LocalDB + for (int j = 0; j < returnSync.getUsers().size(); j++) { + for (int k = 0; k < getChats().size(); k++) { + if (getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) { + + getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus()); + System.out.println(getChats().get(k).getRecipient().getStatus().toString()); + } + } + } + + sync.getMessages().clear(); + sync.getUsers().clear(); + + } + + /** + * Adds a message to the "sync" Sync object. + * + * @param message + * @since Envoy v0.1-alpha + */ + public void addMessageToSync(Message message) { sync.getMessages().add(message); } + + /** + * Adds a user to the "sync" Sync object. + * + * @param user + * @since Envoy v0.1-alpha + */ + public void addUserToSync(User user) { sync.getUsers().add(user); } + + /** + * Adds the unread Messages returned from the server in the latest sync to the + * right chats in the LocalDB. + * + * @param localDB + * @since Envoy v0.1-alpha + */ + public void addUnreadMessagesToLocalDB() { + Sync unreadMessages = unreadMessagesSync; + for (int i = 0; i < unreadMessages.getMessages().size(); i++) + for (int j = 0; j < getChats().size(); j++) + if (getChats().get(j).getRecipient().getID() == unreadMessages.getMessages() + .get(i) + .getMetadata() + .getSender()) { + getChats().get(j).appendMessage(unreadMessages.getMessages().get(i)); + } + } + + /** + * Gets all Messages with state SENT from the LocalDB and adds them to the + * "sync" Sync object. + * + * @param localDB + * @since Envoy v0.1-alpha + */ + public void getSentStateMessagesFromLocalDB() { + for (int i = 0; i < getChats().size(); i++) { + for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) { + if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.SENT) { + addMessageToSync(getChats().get(i).getModel().get(j)); + } + } + } + } + + /** + * Changes all Messages with State RECEIVED of a specific chat to State READ. + *
+ * Adds these Messages to the "readMessages" Sync object. + * + * @param currentChat + * @since Envoy v0.1-alpha + */ + public void setMessagesToRead(Chat currentChat) { + for (int j = 0; j < currentChat.getModel().getSize(); j++) { + if (currentChat.getModel().get(j).getMetadata().getRecipient() != currentChat.getRecipient().getID()) { + if (currentChat.getModel().get(j).getMetadata().getState() == MessageState.RECEIVED) { + currentChat.getModel().get(j).getMetadata().setState(MessageState.READ); + readMessages.getMessages().add(currentChat.getModel().get(j)); + } + } + } + } + + /** + * Adds a Message with State WAITING to a specific chat in the LocalDB. + * + * @param message + * @param currentChat + * @since Envoy v0.1-alpha + */ + public void addWaitingMessageToLocalDB(Message message, Chat currentChat) { currentChat.appendMessage(message); } + + /** + * Adds all Messages with State WAITING from the LocalDB to the Sync. + * + * @param localDB + * @since Envoy v0.1-alpha + */ + public void addWaitingMessagesToSync() { + for (int i = 0; i < getChats().size(); i++) { + for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) { + if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.WAITING) { + // addMessageToSync(localDB.getChats().get(i).getModel().get(j)); + System.out.println("Got Waiting Message"); + sync.getMessages().add(0, getChats().get(i).getModel().get(j)); + } + } + } + } + + + /** + * Clears the "unreadMessagesSync" Sync object. + * + * @since Envoy v0.1-alpha + */ + public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } + + /** * @return all saves {@link Chat} objects that list the client user as the * sender diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 490308d..545715e 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -30,7 +30,6 @@ import envoy.schema.Message; import envoy.schema.Sync; import envoy.schema.User; - /** * Project: envoy-client
* File: ChatWindow.java
@@ -156,8 +155,9 @@ public class ChatWindow extends JFrame { if (!messageEnterTextfield.getText().isEmpty()) try { // Create and send message object - final Message message = client.createMessage(messageEnterTextfield.getText()); - client.addWaitingMessageToLocalDB(message, currentChat); + final Message message = localDB.createMessage(messageEnterTextfield.getText(), + currentChat.getRecipient()); + localDB.addWaitingMessageToLocalDB(message, currentChat); messageList.setModel(currentChat.getModel()); // Clear text field @@ -208,14 +208,12 @@ public class ChatWindow extends JFrame { client.setRecipient(user); textPane.setText(currentChat.getRecipient().getName()); - + messageList.setModel(currentChat.getModel()); contentPane.revalidate(); } }); - - - + userList.setSelectionForeground(new Color(255, 255, 255)); userList.setSelectionBackground(new Color(102, 0, 153)); userList.setForeground(new Color(255, 255, 255)); @@ -233,9 +231,8 @@ public class ChatWindow extends JFrame { contentPane.add(userList, gbc_userList); contentPane.revalidate(); - loadUsersAndChats(); - startReceiverThread(5000); + startSyncThread(5000); contentPane.revalidate(); } @@ -266,20 +263,23 @@ public class ChatWindow extends JFrame { * the server * @since Envoy v0.1-alpha */ - private void startReceiverThread(int timeout) { + private void startSyncThread(int timeout) { new Timer(timeout, (evt) -> { - if(currentChat != null) { - client.setMessagesToRead(currentChat); - } - client.sendSync(client.getSender().getID(), localDB); - client.addUnreadMessagesToLocalDB(localDB); - client.clearUnreadMessagesSync(); - - updateUserStates(); - - contentPane.revalidate(); - contentPane.repaint(); + if (currentChat != null) { localDB.setMessagesToRead(currentChat); } + + new Thread(() -> { + + // Synchronize + localDB.applySync( + client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + localDB.addUnreadMessagesToLocalDB(); + localDB.clearUnreadMessagesSync(); + + // Update UI + SwingUtilities + .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); }).start(); + }).start(); } private void updateUserStates() { From b8f05578fe6b7c8d4aa0dd0e0cd3af813cf8120b Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 9 Nov 2019 13:29:47 +0100 Subject: [PATCH 055/474] Removed unnecessary TODO item --- src/main/java/envoy/client/LocalDB.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index e63fc72..53cd1eb 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -107,7 +107,6 @@ public class LocalDB { } } - // TODO /** * Creates a {@link Message} object serializable to XML. * From f0a72d585119509e52c1b4b03b7d6b501a0aaeb1 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 9 Nov 2019 13:35:17 +0100 Subject: [PATCH 056/474] Fixed grammar --- src/main/java/envoy/client/LocalDB.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 53cd1eb..11b5526 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -253,7 +253,7 @@ public class LocalDB { } } - // Updating UserStatus of all Users in LocalDB + // Updating UserStatus of all users in LocalDB for (int j = 0; j < returnSync.getUsers().size(); j++) { for (int k = 0; k < getChats().size(); k++) { if (getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) { @@ -278,7 +278,7 @@ public class LocalDB { public void addMessageToSync(Message message) { sync.getMessages().add(message); } /** - * Adds a user to the "sync" Sync object. + * Adds a user to the {@code sync} {@link Sync} object. * * @param user * @since Envoy v0.1-alpha @@ -286,7 +286,7 @@ public class LocalDB { public void addUserToSync(User user) { sync.getUsers().add(user); } /** - * Adds the unread Messages returned from the server in the latest sync to the + * Adds the unread messages returned from the server in the latest sync to the * right chats in the LocalDB. * * @param localDB @@ -305,7 +305,7 @@ public class LocalDB { } /** - * Gets all Messages with state SENT from the LocalDB and adds them to the + * Gets all messages with state SENT from the LocalDB and adds them to the * "sync" Sync object. * * @param localDB @@ -322,9 +322,9 @@ public class LocalDB { } /** - * Changes all Messages with State RECEIVED of a specific chat to State READ. + * Changes all messages with State RECEIVED of a specific chat to State READ. *
- * Adds these Messages to the "readMessages" Sync object. + * Adds these Messages to the {@code readMessages} {@link Sync} object. * * @param currentChat * @since Envoy v0.1-alpha @@ -341,7 +341,7 @@ public class LocalDB { } /** - * Adds a Message with State WAITING to a specific chat in the LocalDB. + * Adds a message with State WAITING to a specific chat in the LocalDB. * * @param message * @param currentChat @@ -350,7 +350,7 @@ public class LocalDB { public void addWaitingMessageToLocalDB(Message message, Chat currentChat) { currentChat.appendMessage(message); } /** - * Adds all Messages with State WAITING from the LocalDB to the Sync. + * Adds all messages with State WAITING from the {@link LocalDB} to the Sync. * * @param localDB * @since Envoy v0.1-alpha @@ -369,7 +369,7 @@ public class LocalDB { /** - * Clears the "unreadMessagesSync" Sync object. + * Clears the {@code unreadMessagesSync} {@link Sync} object. * * @since Envoy v0.1-alpha */ From 8cc132eeb532c01cff6bd08c077146cf503be42a Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 9 Nov 2019 13:37:51 +0100 Subject: [PATCH 057/474] Removed empty lines --- src/main/java/envoy/client/LocalDB.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 11b5526..fb69a94 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -366,8 +366,7 @@ public class LocalDB { } } } - - + /** * Clears the {@code unreadMessagesSync} {@link Sync} object. * @@ -375,7 +374,6 @@ public class LocalDB { */ public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } - /** * @return all saves {@link Chat} objects that list the client user as the * sender From 817117905dc8c0b2fa2fbf1c30446b8c1bb9632e Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 9 Nov 2019 14:06:09 +0100 Subject: [PATCH 058/474] Fixed reading messages Fixes #23 --- src/main/java/envoy/client/Client.java | 5 - src/main/java/envoy/client/LocalDB.java | 127 ++++++++---------- src/main/java/envoy/client/ui/ChatWindow.java | 5 +- 3 files changed, 57 insertions(+), 80 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index ed2ff22..f56cfe4 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,6 +1,5 @@ package envoy.client; -import java.time.Instant; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; @@ -8,11 +7,7 @@ import javax.ws.rs.core.Response; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeFactory; -import envoy.schema.Message; -import envoy.schema.Message.Metadata.MessageState; import envoy.schema.ObjectFactory; import envoy.schema.Sync; import envoy.schema.User; diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index fb69a94..e0ff7c1 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -10,18 +10,15 @@ import java.time.Instant; import java.util.ArrayList; import java.util.List; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import envoy.exception.EnvoyException; import envoy.schema.Message; -import envoy.schema.User; import envoy.schema.Message.Metadata.MessageState; import envoy.schema.ObjectFactory; import envoy.schema.Sync; +import envoy.schema.User; /** * Project: envoy-client
@@ -29,6 +26,7 @@ import envoy.schema.Sync; * Created: 27.10.2019
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy v0.1-alpha */ public class LocalDB { @@ -130,27 +128,26 @@ public class LocalDB { return message; } - + private Sync unreadMessagesSync = objectFactory.createSync(); public Sync sync = objectFactory.createSync(); public Sync readMessages = objectFactory.createSync(); - - public Sync fillSync(long userId) { - - addWaitingMessagesToSync(); - getSentStateMessagesFromLocalDB(); - for (int i = 0; i < readMessages.getMessages().size(); i++) { - sync.getMessages().add(readMessages.getMessages().get(i)); - } - readMessages.getMessages().clear(); - + public Sync fillSync(long userId) { + + addWaitingMessagesToSync(); + + getSentStateMessagesFromLocalDB(); + for (int i = 0; i < readMessages.getMessages().size(); i++) { + sync.getMessages().add(readMessages.getMessages().get(i)); + } + readMessages.getMessages().clear(); System.out.println(sync.getMessages().size()); return sync; } - - public void applySync (Sync returnSync) { + + public void applySync(Sync returnSync) { for (int i = 0; i < returnSync.getMessages().size(); i++) { if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.SENT) { @@ -167,37 +164,34 @@ public class LocalDB { .getMetadata() .setState(returnSync.getMessages().get(j).getMetadata().getState()); } - + } - + } if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() != 0 && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { // these are the unread Messages from the server unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); - + } - + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() == 0 && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { // Update Messages in localDB to state RECEIVED for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j).getRecipient().getID() == returnSync.getMessages() - .get(i) - .getMetadata() - .getRecipient()) { + if (getChats().get(j) + .getRecipient() + .getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats() - .get(j) - .getModel() - .get(k) + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync + .getMessages() + .get(i) .getMetadata() - .getMessageId() == returnSync.getMessages().get(i).getMetadata().getMessageId()) { + .getMessageId()) { // Update Message in LocalDB - getChats() - .get(j) + getChats().get(j) .getModel() .get(k) .getMetadata() @@ -206,50 +200,40 @@ public class LocalDB { } } } - + } - + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) { // Update local Messages to state READ - System.out - .println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() - + "was initialized to be set to READ in localDB."); + System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + + "was initialized to be set to READ in localDB."); for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j).getRecipient().getID() == returnSync.getMessages() - .get(i) - .getMetadata() - .getRecipient()) { - System.out.println( - "Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); + if (getChats().get(j) + .getRecipient() + .getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats() - .get(j) - .getModel() - .get(k) + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync + .getMessages() + .get(i) .getMetadata() - .getMessageId() == returnSync.getMessages().get(i).getMetadata().getMessageId()) { + .getMessageId()) { System.out.println("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + "was selected."); - getChats() - .get(j) + getChats().get(j) .getModel() .get(k) .getMetadata() .setState(returnSync.getMessages().get(i).getMetadata().getState()); - System.out.println("Message State is now: " + getChats() - .get(j) - .getModel() - .get(k) - .getMetadata() - .getState() - .toString()); + System.out.println("Message State is now: " + + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); } } } } - + } } @@ -257,13 +241,13 @@ public class LocalDB { for (int j = 0; j < returnSync.getUsers().size(); j++) { for (int k = 0; k < getChats().size(); k++) { if (getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) { - + getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus()); System.out.println(getChats().get(k).getRecipient().getStatus().toString()); } } } - + sync.getMessages().clear(); sync.getUsers().clear(); @@ -296,10 +280,9 @@ public class LocalDB { Sync unreadMessages = unreadMessagesSync; for (int i = 0; i < unreadMessages.getMessages().size(); i++) for (int j = 0; j < getChats().size(); j++) - if (getChats().get(j).getRecipient().getID() == unreadMessages.getMessages() - .get(i) - .getMetadata() - .getSender()) { + if (getChats().get(j) + .getRecipient() + .getID() == unreadMessages.getMessages().get(i).getMetadata().getSender()) { getChats().get(j).appendMessage(unreadMessages.getMessages().get(i)); } } @@ -330,14 +313,12 @@ public class LocalDB { * @since Envoy v0.1-alpha */ public void setMessagesToRead(Chat currentChat) { - for (int j = 0; j < currentChat.getModel().getSize(); j++) { - if (currentChat.getModel().get(j).getMetadata().getRecipient() != currentChat.getRecipient().getID()) { - if (currentChat.getModel().get(j).getMetadata().getState() == MessageState.RECEIVED) { - currentChat.getModel().get(j).getMetadata().setState(MessageState.READ); - readMessages.getMessages().add(currentChat.getModel().get(j)); - } - } - } + for (int i = currentChat.getModel().size() - 1; i >= 0; --i) + if (currentChat.getModel().get(i).getMetadata().getRecipient() != currentChat.getRecipient().getID()) + if (currentChat.getModel().get(i).getMetadata().getState() == MessageState.RECEIVED) { + currentChat.getModel().get(i).getMetadata().setState(MessageState.READ); + readMessages.getMessages().add(currentChat.getModel().get(i)); + } else break; } /** @@ -373,7 +354,7 @@ public class LocalDB { * @since Envoy v0.1-alpha */ public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } - + /** * @return all saves {@link Chat} objects that list the client user as the * sender diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 545715e..c6e8c37 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -205,6 +205,9 @@ public class ChatWindow extends JFrame { .findFirst() .get(); + // Set all unread messages in the chat to read + if (currentChat != null) { localDB.setMessagesToRead(currentChat); } + client.setRecipient(user); textPane.setText(currentChat.getRecipient().getName()); @@ -265,8 +268,6 @@ public class ChatWindow extends JFrame { */ private void startSyncThread(int timeout) { new Timer(timeout, (evt) -> { - if (currentChat != null) { localDB.setMessagesToRead(currentChat); } - new Thread(() -> { // Synchronize From a9b32249243650f4f23d85463ead89223d196de4 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 9 Nov 2019 14:23:26 +0100 Subject: [PATCH 059/474] Edit syncTimeout property, made Config a singleton --- src/main/java/envoy/client/Config.java | 22 +++++++++++++++++-- src/main/java/envoy/client/ui/ChatWindow.java | 5 +++-- .../envoy/client/ui/MessageListRenderer.java | 2 +- src/main/java/envoy/client/ui/Startup.java | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 0da3cf1..c31c972 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -16,6 +16,16 @@ public class Config { private String server; private int port; private File localDB; + private int syncTimeout; + + private static Config config; + + private Config() {} + + public static Config getInstance() { + if (config == null) config = new Config(); + return config; + } /** * Defaults to the {@code client.properties} file for information. @@ -28,7 +38,8 @@ public class Config { public void load(Properties properties) { if (properties.containsKey("server")) server = properties.getProperty("server"); if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); - localDB = new File(properties.getProperty("localDB", ".\\localDB")); + localDB = new File(properties.getProperty("localDB", ".\\localDB")); + syncTimeout = Integer.parseInt(properties.getProperty("syncTimeout", "1000")); } /** @@ -54,13 +65,16 @@ public class Config { localDB = new File(args[++i]); } if (localDB == null) localDB = new File(".\\localDB"); + if (syncTimeout == 0) syncTimeout = 1000; } /** * @return {@code true} if server, port and localDB directory are known. * @since Envoy v0.1-alpha */ - public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; } + public boolean isInitialized() { + return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; + } /** * @return the host name of the Envoy server @@ -106,4 +120,8 @@ public class Config { * @since Envoy v0.1-alpha **/ public void setLocalDB(File localDB) { this.localDB = localDB; } + + public int getSyncTimeout() { return syncTimeout; } + + public void setSyncTimeout(int syncTimeout) { this.syncTimeout = syncTimeout; } } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index c6e8c37..4a36c57 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -25,6 +25,7 @@ import javax.swing.border.EmptyBorder; import envoy.client.Chat; import envoy.client.Client; +import envoy.client.Config; import envoy.client.LocalDB; import envoy.schema.Message; import envoy.schema.Sync; @@ -235,7 +236,7 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); loadUsersAndChats(); - startSyncThread(5000); + startSyncThread(Config.getInstance().getSyncTimeout()); contentPane.revalidate(); } @@ -260,7 +261,7 @@ public class ChatWindow extends JFrame { } /** - * For detailed information see Javadoc of corresponding methods. + * Updates the data model and the ui every x seconds. * * @param timeout the amount of time that passes between two requests sent to * the server diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 7afdec3..9053c6c 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -41,7 +41,7 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer 0) { config.load(args); } else { From a76f1aa743829704d7acabf2338dc52422c239aa Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 9 Nov 2019 17:47:18 +0100 Subject: [PATCH 060/474] Revised merge conflict changes --- src/main/java/envoy/client/LocalDB.java | 2 +- src/main/java/envoy/client/ui/ChatWindow.java | 68 ++++++++----------- 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 84383b3..142b687 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -367,5 +367,5 @@ public class LocalDB { * @return the User who initialised the local Database * @since Envoy v0.1-alpha */ - public User getUser() { return client; } + public User getUser() { return sender; } } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index e98a476..2a7ae11 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -125,8 +125,8 @@ public class ChatWindow extends JFrame { if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { - postMessage(client, messageList); + postMessage(messageList); } } @@ -164,42 +164,9 @@ public class ChatWindow extends JFrame { gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); + postButton.addActionListener((evt) -> { postMessage(messageList); }); + contentPane.add(postButton, gbc_moveSelectionPostButton); - postButton.addActionListener((evt) -> { - if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, - "Please select a recipient!", - "Cannot send message", - JOptionPane.INFORMATION_MESSAGE); - } - - // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), - currentChat.getRecipient()); - localDB.addWaitingMessageToLocalDB(message, currentChat); - messageList.setModel(currentChat.getModel()); - - contentPane.add(postButton, gbc_moveSelectionPostButton); - - if (!messageEnterTextArea.getText().isEmpty()) try { - - // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient()); - localDB.addWaitingMessageToLocalDB(message, currentChat); - messageList.setModel(currentChat.getModel()); - - // Clear text field - messageEnterTextArea.setText(""); - contentPane.revalidate(); - } catch (Exception e) { - JOptionPane.showMessageDialog(this, - "An exception occured while sending a message. See the log for more details.", - "Exception occured", - JOptionPane.ERROR_MESSAGE); - e.printStackTrace(); - }); - - // Settings Button JButton settingsButton = new JButton("Settings"); settingsButton.setForeground(new Color(255, 255, 255)); @@ -208,7 +175,6 @@ public class ChatWindow extends JFrame { GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); - gbc_moveSelectionSettingsButton.fill = GridBagConstraints.BOTH; gbc_moveSelectionSettingsButton.gridx = 2; gbc_moveSelectionSettingsButton.gridy = 0; @@ -291,7 +257,33 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); } - + private void postMessage(JList messageList) { + if (!client.hasRecipient()) { + JOptionPane.showMessageDialog(this, + "Please select a recipient!", + "Cannot send message", + JOptionPane.INFORMATION_MESSAGE); + } + + if (!messageEnterTextArea.getText().isEmpty()) try { + + // Create and send message object + final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient()); + localDB.addWaitingMessageToLocalDB(message, currentChat); + messageList.setModel(currentChat.getModel()); + + // Clear text field + messageEnterTextArea.setText(""); + contentPane.revalidate(); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "An exception occured while sending a message. See the log for more details.", + "Exception occured", + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + /** * Initializes the elements of the user list by downloading them from the * server. From bbdf17d17b00e6aae4378f9110bcdee7603d2d40 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 13 Nov 2019 05:59:51 +0100 Subject: [PATCH 061/474] Loading config from properties before command line args --- src/main/java/envoy/client/Config.java | 4 +-- src/main/java/envoy/client/ui/Startup.java | 34 ++++++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index c31c972..545df2f 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -32,7 +32,7 @@ public class Config { * * @param properties a {@link Properties} object containing information about * the server and port, as well as the path to the local - * database + * database and the synchronization timeout * @since Envoy v0.1-alpha */ public void load(Properties properties) { @@ -64,8 +64,6 @@ public class Config { case "-db": localDB = new File(args[++i]); } - if (localDB == null) localDB = new File(".\\localDB"); - if (syncTimeout == 0) syncTimeout = 1000; } /** diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index c3a3baa..5a2d92f 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -26,21 +26,24 @@ public class Startup { public static void main(String[] args) { Config config = Config.getInstance(); - if (args.length > 0) { - config.load(args); - } else { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - try { - Properties configProperties = new Properties(); - configProperties.load(loader.getResourceAsStream("client.properties")); - config.load(configProperties); - } catch (IOException e) { - e.printStackTrace(); - } + + // Load the configuration from client.properties first + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + try { + Properties configProperties = new Properties(); + configProperties.load(loader.getResourceAsStream("client.properties")); + config.load(configProperties); + } catch (IOException e) { + e.printStackTrace(); } + // Override configuration values with command line arguments + if (args.length > 0) + config.load(args); + if (!config.isInitialized()) { - System.err.println("Server or port are not defined. Exiting..."); + JOptionPane.showMessageDialog(null, "Error loading configuration values.", "Configuration error", + JOptionPane.ERROR_MESSAGE); System.exit(1); } @@ -49,16 +52,15 @@ public class Startup { System.err.println("User name is not set or empty. Exiting..."); System.exit(1); } - Client client = new Client(config, userName); - LocalDB localDB = new LocalDB(client.getSender()); + Client client = new Client(config, userName); + LocalDB localDB = new LocalDB(client.getSender()); try { localDB.initializeDBFile(config.getLocalDB()); } catch (EnvoyException e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", - "Local DB error", - JOptionPane.WARNING_MESSAGE); + "Local DB error", JOptionPane.WARNING_MESSAGE); } EventQueue.invokeLater(() -> { From 73eb312a908a52db6c3fa401ab9e44896139423d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 16 Nov 2019 08:06:07 +0100 Subject: [PATCH 062/474] Mark all newly received messages in the current chat as read Fixes #24 --- src/main/java/envoy/client/LocalDB.java | 95 ++++++------------- src/main/java/envoy/client/ui/ChatWindow.java | 12 ++- 2 files changed, 42 insertions(+), 65 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 142b687..29d7a5c 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -30,12 +30,17 @@ import envoy.schema.User; * @since Envoy v0.1-alpha */ public class LocalDB { + private File localDB; private User sender; private List chats = new ArrayList<>(); private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; + private Sync unreadMessagesSync = objectFactory.createSync(); + private Sync sync = objectFactory.createSync(); + private Sync readMessages = objectFactory.createSync(); + /** * Constructs an empty local database. * @@ -51,7 +56,6 @@ public class LocalDB { e.printStackTrace(); } } - /** * Initializes the local database and fills it with values @@ -62,8 +66,8 @@ public class LocalDB { * @since Envoy v0.1-alpha **/ public void initializeDBFile(File localDBDir) throws EnvoyException { - if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException( - String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); + if (localDBDir.exists() && !localDBDir.isDirectory()) + throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); localDB = new File(localDBDir, sender.getID() + ".db"); if (localDB.exists()) loadFromLocalDB(); } @@ -130,12 +134,7 @@ public class LocalDB { return message; } - private Sync unreadMessagesSync = objectFactory.createSync(); - public Sync sync = objectFactory.createSync(); - public Sync readMessages = objectFactory.createSync(); - public Sync fillSync(long userId) { - addWaitingMessagesToSync(); getSentStateMessagesFromLocalDB(); @@ -156,47 +155,32 @@ public class LocalDB { // SENT) for (int j = 0; j < sync.getMessages().size(); j++) { if (j == i) { - sync.getMessages() - .get(j) - .getMetadata() - .setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId()); - sync.getMessages() - .get(j) - .getMetadata() - .setState(returnSync.getMessages().get(j).getMetadata().getState()); + sync.getMessages().get(j).getMetadata().setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId()); + sync.getMessages().get(j).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState()); } } } - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 - && returnSync.getMessages().get(i).getMetadata().getSender() != 0 + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() != 0 && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { // these are the unread Messages from the server unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); } - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 - && returnSync.getMessages().get(i).getMetadata().getSender() == 0 + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() == 0 && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { // Update Messages in localDB to state RECEIVED for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j) - .getRecipient() - .getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync - .getMessages() + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() .get(i) .getMetadata() .getMessageId()) { // Update Message in LocalDB - getChats().get(j) - .getModel() - .get(k) - .getMetadata() - .setState(returnSync.getMessages().get(j).getMetadata().getState()); + getChats().get(j).getModel().get(k).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState()); } } } @@ -210,26 +194,18 @@ public class LocalDB { System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + "was initialized to be set to READ in localDB."); for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j) - .getRecipient() - .getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync - .getMessages() + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() .get(i) .getMetadata() .getMessageId()) { - System.out.println("Message with ID: " - + getChats().get(j).getModel().get(k).getMetadata().getMessageId() - + "was selected."); - getChats().get(j) - .getModel() - .get(k) - .getMetadata() - .setState(returnSync.getMessages().get(i).getMetadata().getState()); - System.out.println("Message State is now: " - + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); + System.out.println( + "Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + "was selected."); + getChats().get(j).getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + System.out + .println("Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); } } } @@ -260,15 +236,7 @@ public class LocalDB { * @param message * @since Envoy v0.1-alpha */ - public void addMessageToSync(Message message) { sync.getMessages().add(message); } - - /** - * Adds a user to the {@code sync} {@link Sync} object. - * - * @param user - * @since Envoy v0.1-alpha - */ - public void addUserToSync(User user) { sync.getUsers().add(user); } + private void addMessageToSync(Message message) { sync.getMessages().add(message); } /** * Adds the unread messages returned from the server in the latest sync to the @@ -281,21 +249,19 @@ public class LocalDB { Sync unreadMessages = unreadMessagesSync; for (int i = 0; i < unreadMessages.getMessages().size(); i++) for (int j = 0; j < getChats().size(); j++) - if (getChats().get(j) - .getRecipient() - .getID() == unreadMessages.getMessages().get(i).getMetadata().getSender()) { + if (getChats().get(j).getRecipient().getID() == unreadMessages.getMessages().get(i).getMetadata().getSender()) { getChats().get(j).appendMessage(unreadMessages.getMessages().get(i)); } } /** - * Gets all messages with state SENT from the LocalDB and adds them to the - * "sync" Sync object. + * Gets all messages with state {@code SENT} from the LocalDB and adds them to + * the {@code sync} {@link Sync} object. * * @param localDB * @since Envoy v0.1-alpha */ - public void getSentStateMessagesFromLocalDB() { + private void getSentStateMessagesFromLocalDB() { for (int i = 0; i < getChats().size(); i++) { for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) { if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.SENT) { @@ -306,9 +272,10 @@ public class LocalDB { } /** - * Changes all messages with State RECEIVED of a specific chat to State READ. + * Changes all messages with state {@code RECEIVED} of a specific chat to state + * {@code READ}. *
- * Adds these Messages to the {@code readMessages} {@link Sync} object. + * Adds these messages to the {@code readMessages} {@link Sync} object. * * @param currentChat * @since Envoy v0.1-alpha @@ -337,7 +304,7 @@ public class LocalDB { * @param localDB * @since Envoy v0.1-alpha */ - public void addWaitingMessagesToSync() { + private void addWaitingMessagesToSync() { for (int i = 0; i < getChats().size(); i++) { for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) { if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.WAITING) { @@ -364,7 +331,7 @@ public class LocalDB { public List getChats() { return chats; } /** - * @return the User who initialised the local Database + * @return the {@link User} who initialized the local database * @since Envoy v0.1-alpha */ public User getUser() { return sender; } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 2a7ae11..66b750f 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -223,7 +223,7 @@ public class ChatWindow extends JFrame { .get(); // Set all unread messages in the chat to read - if (currentChat != null) { localDB.setMessagesToRead(currentChat); } + readCurrentChat(); client.setRecipient(user); @@ -319,9 +319,14 @@ public class ChatWindow extends JFrame { // Synchronize localDB.applySync( client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + + // Process unread messages localDB.addUnreadMessagesToLocalDB(); localDB.clearUnreadMessagesSync(); + // Mark unread messages as read when they are in the current chat + readCurrentChat(); + // Update UI SwingUtilities .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); @@ -335,4 +340,9 @@ public class ChatWindow extends JFrame { if (userList.getModel().getElementAt(i).getID() == localDB.getChats().get(j).getRecipient().getID()) userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); } + + /** + * Marks messages in the current chat as {@code READ}. + */ + private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } } \ No newline at end of file From eadccd71266f9c512261e8d1119ae7c6bc4cfe7e Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 16 Nov 2019 08:23:04 +0100 Subject: [PATCH 063/474] Preventing sent messages from being added to the sync again Fixed #25 --- src/main/java/envoy/client/LocalDB.java | 45 +++---------------- src/main/java/envoy/client/ui/ChatWindow.java | 3 +- 2 files changed, 9 insertions(+), 39 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 29d7a5c..ace6881 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -137,10 +137,7 @@ public class LocalDB { public Sync fillSync(long userId) { addWaitingMessagesToSync(); - getSentStateMessagesFromLocalDB(); - for (int i = 0; i < readMessages.getMessages().size(); i++) { - sync.getMessages().add(readMessages.getMessages().get(i)); - } + sync.getMessages().addAll(readMessages.getMessages()); readMessages.getMessages().clear(); System.out.println(sync.getMessages().size()); @@ -230,14 +227,6 @@ public class LocalDB { } - /** - * Adds a message to the "sync" Sync object. - * - * @param message - * @since Envoy v0.1-alpha - */ - private void addMessageToSync(Message message) { sync.getMessages().add(message); } - /** * Adds the unread messages returned from the server in the latest sync to the * right chats in the LocalDB. @@ -254,23 +243,6 @@ public class LocalDB { } } - /** - * Gets all messages with state {@code SENT} from the LocalDB and adds them to - * the {@code sync} {@link Sync} object. - * - * @param localDB - * @since Envoy v0.1-alpha - */ - private void getSentStateMessagesFromLocalDB() { - for (int i = 0; i < getChats().size(); i++) { - for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) { - if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.SENT) { - addMessageToSync(getChats().get(i).getModel().get(j)); - } - } - } - } - /** * Changes all messages with state {@code RECEIVED} of a specific chat to state * {@code READ}. @@ -299,21 +271,18 @@ public class LocalDB { public void addWaitingMessageToLocalDB(Message message, Chat currentChat) { currentChat.appendMessage(message); } /** - * Adds all messages with State WAITING from the {@link LocalDB} to the Sync. + * Adds all messages with state {@code WAITING} from the {@link LocalDB} to the + * {@link Sync} object. * - * @param localDB * @since Envoy v0.1-alpha */ private void addWaitingMessagesToSync() { - for (int i = 0; i < getChats().size(); i++) { - for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) { - if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.WAITING) { - // addMessageToSync(localDB.getChats().get(i).getModel().get(j)); + for (Chat chat : getChats()) + for (int i = 0; i < chat.getModel().size(); i++) + if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) { System.out.println("Got Waiting Message"); - sync.getMessages().add(0, getChats().get(i).getModel().get(j)); + sync.getMessages().add(chat.getModel().get(i)); } - } - } } /** diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 66b750f..48d3bdc 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -306,7 +306,8 @@ public class ChatWindow extends JFrame { } /** - * Updates the data model and the ui every x seconds. + * Updates the data model and the UI every repeatedly after a certain amount of + * time. * * @param timeout the amount of time that passes between two requests sent to * the server From b657f2a516ef3799a2bbfbda0910359aedf67894 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 16 Nov 2019 10:47:32 +0100 Subject: [PATCH 064/474] Removed LocalDB#addWaitingMessageToLocalDB, fixed formatting --- src/main/java/envoy/client/LocalDB.java | 22 ++++--------------- src/main/java/envoy/client/ui/ChatWindow.java | 2 +- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index ace6881..3cc96a2 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -46,7 +46,7 @@ public class LocalDB { * * @param client the user that is logged in with this client * @since Envoy v0.1-alpha - **/ + */ public LocalDB(User sender) { this.sender = sender; @@ -64,7 +64,7 @@ public class LocalDB { * @param localDBDir the directory where we wish to save/load the database from. * @throws EnvoyException if the directory selected is not an actual directory. * @since Envoy v0.1-alpha - **/ + */ public void initializeDBFile(File localDBDir) throws EnvoyException { if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); @@ -77,7 +77,7 @@ public class LocalDB { * * @throws IOException if something went wrong during saving * @since Envoy v0.1-alpha - **/ + */ public void saveToLocalDB() { try { localDB.getParentFile().mkdirs(); @@ -99,7 +99,7 @@ public class LocalDB { * * @throws EnvoyException if something fails while loading. * @since Envoy v0.1-alpha - **/ + */ @SuppressWarnings("unchecked") private void loadFromLocalDB() throws EnvoyException { try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(localDB))) { @@ -155,15 +155,12 @@ public class LocalDB { sync.getMessages().get(j).getMetadata().setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId()); sync.getMessages().get(j).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState()); } - } - } if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() != 0 && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { // these are the unread Messages from the server unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); - } if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() == 0 @@ -207,7 +204,6 @@ public class LocalDB { } } } - } } @@ -224,7 +220,6 @@ public class LocalDB { sync.getMessages().clear(); sync.getUsers().clear(); - } /** @@ -261,15 +256,6 @@ public class LocalDB { } else break; } - /** - * Adds a message with State WAITING to a specific chat in the LocalDB. - * - * @param message - * @param currentChat - * @since Envoy v0.1-alpha - */ - public void addWaitingMessageToLocalDB(Message message, Chat currentChat) { currentChat.appendMessage(message); } - /** * Adds all messages with state {@code WAITING} from the {@link LocalDB} to the * {@link Sync} object. diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 48d3bdc..b9aea74 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -269,7 +269,7 @@ public class ChatWindow extends JFrame { // Create and send message object final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient()); - localDB.addWaitingMessageToLocalDB(message, currentChat); + currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); // Clear text field From 5e4e1449d2a079d58d9b4306369f42d38963ab51 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 16 Nov 2019 14:16:27 +0100 Subject: [PATCH 065/474] updated Javadoc --- src/main/java/envoy/client/ui/ChatWindow.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index b9aea74..32b024b 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -306,7 +306,7 @@ public class ChatWindow extends JFrame { } /** - * Updates the data model and the UI every repeatedly after a certain amount of + * Updates the data model and the UI repeatedly after a certain amount of * time. * * @param timeout the amount of time that passes between two requests sent to @@ -346,4 +346,4 @@ public class ChatWindow extends JFrame { * Marks messages in the current chat as {@code READ}. */ private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } -} \ No newline at end of file +} From 48b9176ac2e33ef21aa6efae55dcff73ed92c606 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 22 Nov 2019 06:37:59 +0100 Subject: [PATCH 066/474] Implemented settings object and cleaned up ChatWindow Improvements: * Settings were implemented * Light theme support was implemented * The readability of ChatWindow got improved --- src/main/java/envoy/client/Config.java | 16 +- src/main/java/envoy/client/LocalDB.java | 39 ++-- src/main/java/envoy/client/Settings.java | 129 ++++++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 130 +++++++----- .../java/envoy/client/ui/SettingsScreen.java | 187 ++++++++---------- src/main/java/envoy/client/ui/Startup.java | 4 +- src/main/java/envoy/client/ui/UIColors.java | 158 +++++++++++++++ .../envoy/client/ui/UserListRenderer.java | 6 + 8 files changed, 492 insertions(+), 177 deletions(-) create mode 100644 src/main/java/envoy/client/Settings.java create mode 100644 src/main/java/envoy/client/ui/UIColors.java diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index c31c972..fd83299 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -63,6 +63,7 @@ public class Config { case "--localDB": case "-db": localDB = new File(args[++i]); + break; } if (localDB == null) localDB = new File(".\\localDB"); if (syncTimeout == 0) syncTimeout = 1000; @@ -115,13 +116,24 @@ public class Config { /** * Changes the default local database. * Exclusively intended for development purposes. - * - * @param the file containing the local database + * + * @param localDB the file containing the local database * @since Envoy v0.1-alpha **/ public void setLocalDB(File localDB) { this.localDB = localDB; } + /** + * + * @return the current time (milliseconds) that is waited between Syncs + * @since Envoy v0.1-alpha + */ public int getSyncTimeout() { return syncTimeout; } + /** + * + * @param syncTimeout sets the time (milliseconds) during which Sync waits + * @since Envoy v0.1-alpha + */ public void setSyncTimeout(int syncTimeout) { this.syncTimeout = syncTimeout; } + } diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 142b687..5b702e8 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -30,8 +30,10 @@ import envoy.schema.User; * @since Envoy v0.1-alpha */ public class LocalDB { + private File localDB; private User sender; + private final long id; private List chats = new ArrayList<>(); private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; @@ -39,19 +41,19 @@ public class LocalDB { /** * Constructs an empty local database. * - * @param client the user that is logged in with this client + * @param sender the user that is logged in with this client * @since Envoy v0.1-alpha **/ public LocalDB(User sender) { - this.sender = sender; + this.sender = sender; + id = sender.getID(); try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException e) { e.printStackTrace(); } } - /** * Initializes the local database and fills it with values @@ -64,14 +66,16 @@ public class LocalDB { public void initializeDBFile(File localDBDir) throws EnvoyException { if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException( String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - localDB = new File(localDBDir, sender.getID() + ".db"); + localDB = new File(localDBDir, id + ".db"); if (localDB.exists()) loadFromLocalDB(); } /** - * Saves the database into a file for future use. + * Saves the database into a file for future use.
+ * It is theoretically possible to fail due to unknown causes.
+ * In such a case, every message sent/ received during that session will be + * lost. * - * @throws IOException if something went wrong during saving * @since Envoy v0.1-alpha **/ public void saveToLocalDB() { @@ -110,12 +114,13 @@ public class LocalDB { * Creates a {@link Message} object serializable to XML. * * @param textContent The content (text) of the message + * @param recipientID self explanatory * @return prepared {@link Message} object */ - public Message createMessage(String textContent, User recipient) { + public Message createMessage(String textContent, long recipientID) { Message.Metadata metaData = objectFactory.createMessageMetadata(); metaData.setSender(sender.getID()); - metaData.setRecipient(recipient.getID()); + metaData.setRecipient(recipientID); metaData.setState(MessageState.WAITING); metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); @@ -257,7 +262,7 @@ public class LocalDB { /** * Adds a message to the "sync" Sync object. * - * @param message + * @param message the message to send * @since Envoy v0.1-alpha */ public void addMessageToSync(Message message) { sync.getMessages().add(message); } @@ -274,7 +279,6 @@ public class LocalDB { * Adds the unread messages returned from the server in the latest sync to the * right chats in the LocalDB. * - * @param localDB * @since Envoy v0.1-alpha */ public void addUnreadMessagesToLocalDB() { @@ -292,7 +296,6 @@ public class LocalDB { * Gets all messages with state SENT from the LocalDB and adds them to the * "sync" Sync object. * - * @param localDB * @since Envoy v0.1-alpha */ public void getSentStateMessagesFromLocalDB() { @@ -310,7 +313,7 @@ public class LocalDB { *
* Adds these Messages to the {@code readMessages} {@link Sync} object. * - * @param currentChat + * @param currentChat the chat that was just opened * @since Envoy v0.1-alpha */ public void setMessagesToRead(Chat currentChat) { @@ -325,8 +328,8 @@ public class LocalDB { /** * Adds a message with State WAITING to a specific chat in the LocalDB. * - * @param message - * @param currentChat + * @param message the message that is not yet received by the other user + * @param currentChat the chat that is currently open * @since Envoy v0.1-alpha */ public void addWaitingMessageToLocalDB(Message message, Chat currentChat) { currentChat.appendMessage(message); } @@ -334,7 +337,6 @@ public class LocalDB { /** * Adds all messages with State WAITING from the {@link LocalDB} to the Sync. * - * @param localDB * @since Envoy v0.1-alpha */ public void addWaitingMessagesToSync() { @@ -368,4 +370,11 @@ public class LocalDB { * @since Envoy v0.1-alpha */ public User getUser() { return sender; } + + /** + * @return the id of the client. Used as shortcut for quicker information + * retrieval + * @since Envoy v0.2-alpha + */ + public long getId() { return id; } } diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java new file mode 100644 index 0000000..7377876 --- /dev/null +++ b/src/main/java/envoy/client/Settings.java @@ -0,0 +1,129 @@ +package envoy.client; + +import java.util.prefs.Preferences; + +/** + * Project: envoy-client
+ * File: Settings.java
+ * Created: 11 Nov 2019
+ * + * @author Leon Hofmeister + * @since Envoy v0.2-alpha + */ +public class Settings { + + private String username; + private String email; + private boolean enterToSend = true; + private boolean darkMode = true; + // private Image profilePic; + private static Settings settings; + private Preferences prefs = Preferences.userNodeForPackage(Settings.class); + + /** + * The way to instantiate the settings. + * Is set to private to deny other instances of that object. + * + * @since Envoy v0.2-alpha + */ + private Settings() {} + + /** + * This method is used to ensure that there is only one instance of Settings. + * + * @return the instance of Settings + * @since Envoy v0.2-alpha + */ + public static Settings getInstance() { + if (settings == null) { + settings = new Settings(); + } + settings.load(); + return settings; + } + + public void load() { + settings.setUsername(prefs.get("username", "")); + settings.setEmail(prefs.get("email", "")); + settings.setDarkMode(prefs.getBoolean("darkMode", true)); + settings.setEnterToSend(prefs.getBoolean("enterToSend", true)); + } + + public void save() { + prefs.put("username", settings.getUsername()); + prefs.put("email", settings.getEmail()); + prefs.putBoolean("darkMode", settings.isDarkMode()); + prefs.putBoolean("enterToSend", settings.isEnterToSend()); + } + + /** + * @return the username + * @since Envoy v0.2-alpha + */ + public String getUsername() { return username; } + + /** + * @param username the username to set + * @since Envoy v0.2-alpha + */ + public void setUsername(String username) { this.username = username; } + + /** + * @return the email associated with that user. + * @since Envoy v0.2-alpha + */ + public String getEmail() { return email; } + + /** + * @param email the email to set + * @since Envoy v0.2-alpha + */ + public void setEmail(String email) { this.email = email; } + + /** + * @return true, if "enter" suffices to send a message, else it has to be "ctrl" + * + "enter" + * @since Envoy v0.2-alpha + */ + public boolean isEnterToSend() { return enterToSend; } + + /** + * Change mode of posting a message via Keystroke. + * + * @param enterToSend if true, "enter" suffices to send a message,
+ * else it has to be "ctrl" + "enter" + * @since Envoy v0.2-alpha + */ + public void setEnterToSend(boolean enterToSend) { this.enterToSend = enterToSend; } + + /** + * Describes whether the Envoy GUI should be displayed in dark mode or not. + * + * @return true, if dark mode display is currently set, else the light theme + * will be displayed + * @since Envoy v0.2-alpha + */ + public boolean isDarkMode() { return darkMode; } + + /** + * Change display mode of Envoy GUI. + * + * @param darkMode true, if dark mode display is currently set,
+ * else the light theme will be displayed + * @since Envoy v0.2-alpha + */ + public void setDarkMode(boolean darkMode) { this.darkMode = darkMode; } + + // /** + // * @return the profilePic + // * @since Envoy v0.2-alpha + // */ + // public Image getProfilePic() { return profilePic; } + // + // /** + // * @param profilePic the profilePic to set + // * @since Envoy v0.1-alpha + // */ + // public void setProfilePic(Image profilePic) { this.profilePic = profilePic; } + +} diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 2a7ae11..f2aa7d8 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,6 +1,5 @@ package envoy.client.ui; -import java.awt.Color; import java.awt.ComponentOrientation; import java.awt.Font; import java.awt.GridBagConstraints; @@ -29,6 +28,7 @@ import envoy.client.Chat; import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; +import envoy.client.Settings; import envoy.schema.Message; import envoy.schema.Sync; import envoy.schema.User; @@ -47,19 +47,30 @@ public class ChatWindow extends JFrame { private static final long serialVersionUID = 6865098428255463649L; - private JPanel contentPane = new JPanel(); + // user specific objects + private Client client; + private LocalDB localDB; + private Settings settings; + // used colors in Envoy + private UIColors uiColors = UIColors.getInstance(true); + // GUI components + private JPanel contentPane = new JPanel(); + private JTextArea messageEnterTextArea = new JTextArea(); + private JList userList = new JList<>(); + private Chat currentChat; + private JList messageList = new JList<>(); + private JScrollPane scrollPane = new JScrollPane(); + private JTextPane textPane = new JTextPane(); + // private JCheckBox jCbChangeMode; + private JButton postButton = new JButton(); + private JButton settingsButton = new JButton(); - private Client client; - private LocalDB localDB; + private static int space = 4; - private JList userList = new JList<>(); - private Chat currentChat; - - private JTextArea messageEnterTextArea; - - public ChatWindow(Client client, LocalDB localDB) { + public ChatWindow(Client client, LocalDB localDB, Settings setting) { this.client = client; this.localDB = localDB; + this.settings = setting; setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); @@ -73,9 +84,7 @@ public class ChatWindow extends JFrame { public void windowClosing(WindowEvent e) { localDB.saveToLocalDB(); } }); - contentPane.setBackground(new Color(0, 0, 0)); - contentPane.setForeground(Color.white); - contentPane.setBorder(new EmptyBorder(0, 5, 0, 0)); + contentPane.setBorder(new EmptyBorder(space, space, space, space)); setContentPane(contentPane); GridBagLayout gbl_contentPane = new GridBagLayout(); gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; @@ -84,25 +93,16 @@ public class ChatWindow extends JFrame { gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 }; contentPane.setLayout(gbl_contentPane); - JList messageList = new JList<>(); messageList.setCellRenderer(new MessageListRenderer()); - messageList.setFocusTraversalKeysEnabled(false); - messageList.setSelectionForeground(new Color(255, 255, 255)); - messageList.setSelectionBackground(new Color(102, 0, 153)); messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); - messageList.setForeground(new Color(255, 255, 255)); - messageList.setBackground(new Color(51, 51, 51)); DefaultListModel messageListModel = new DefaultListModel<>(); messageList.setModel(messageListModel); messageList.setFont(new Font("Arial", Font.PLAIN, 17)); messageList.setFixedCellHeight(60); - messageList.setBorder(new EmptyBorder(5, 5, 5, 5)); + messageList.setBorder(new EmptyBorder(space, space, space, space)); - JScrollPane scrollPane = new JScrollPane(); - scrollPane.setForeground(new Color(0, 0, 0)); - scrollPane.setBackground(new Color(51, 51, 51)); scrollPane.setViewportView(messageList); scrollPane.setBorder(null); @@ -112,18 +112,17 @@ public class ChatWindow extends JFrame { gbc_scrollPane.gridx = 1; gbc_scrollPane.gridy = 1; - gbc_scrollPane.insets = new Insets(0, 10, 10, 10); + gbc_scrollPane.insets = new Insets(space, space, space, space); contentPane.add(scrollPane, gbc_scrollPane); // Message enter field - messageEnterTextArea = new JTextArea(); messageEnterTextArea.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) + if (e.getKeyCode() == KeyEvent.VK_ENTER && ((settings.isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); @@ -133,44 +132,34 @@ public class ChatWindow extends JFrame { }); // Checks for changed Message messageEnterTextArea.setWrapStyleWord(true); - messageEnterTextArea.setCaretColor(new Color(255, 255, 255)); - messageEnterTextArea.setForeground(new Color(255, 255, 255)); - messageEnterTextArea.setBackground(new Color(51, 51, 51)); messageEnterTextArea.setLineWrap(true); messageEnterTextArea.setBorder(null); messageEnterTextArea.setFont(new Font("Arial", Font.PLAIN, 17)); - messageEnterTextArea.setBorder(new EmptyBorder(5, 5, 5, 5)); + messageEnterTextArea.setBorder(new EmptyBorder(space, space, space, space)); GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; gbc_messageEnterTextfield.gridx = 1; gbc_messageEnterTextfield.gridy = 2; - gbc_messageEnterTextfield.insets = new Insets(10, 10, 10, 10); + gbc_messageEnterTextfield.insets = new Insets(space, space, space, space); contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); // Post Button - JButton postButton = new JButton("Post"); - postButton.setForeground(new Color(255, 255, 255)); - postButton.setBackground(new Color(102, 51, 153)); postButton.setBorderPainted(false); - GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; gbc_moveSelectionPostButton.gridx = 2; gbc_moveSelectionPostButton.gridy = 2; - gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); + gbc_moveSelectionPostButton.insets = new Insets(space, space, space, space); postButton.addActionListener((evt) -> { postMessage(messageList); }); contentPane.add(postButton, gbc_moveSelectionPostButton); // Settings Button - JButton settingsButton = new JButton("Settings"); - settingsButton.setForeground(new Color(255, 255, 255)); - settingsButton.setBackground(new Color(102, 51, 153)); settingsButton.setBorderPainted(false); GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); @@ -179,13 +168,12 @@ public class ChatWindow extends JFrame { gbc_moveSelectionSettingsButton.gridx = 2; gbc_moveSelectionSettingsButton.gridy = 0; - gbc_moveSelectionSettingsButton.insets = new Insets(10, 10, 10, 10); + gbc_moveSelectionSettingsButton.insets = new Insets(space, space, space, space); settingsButton.addActionListener((evt) -> { try { - SettingsScreen.open(localDB.getUser().getName()); - } catch (Exception e) { SettingsScreen.open(); + } catch (Exception e) { System.err.println("An error occured while opening the settings screen: " + e); e.printStackTrace(); } @@ -193,10 +181,6 @@ public class ChatWindow extends JFrame { contentPane.add(settingsButton, gbc_moveSelectionSettingsButton); // Partner name display - JTextPane textPane = new JTextPane(); - textPane.setBackground(new Color(0, 0, 0)); - textPane.setForeground(new Color(255, 255, 255)); - textPane.setFont(new Font("Arial", Font.PLAIN, 20)); GridBagConstraints gbc_partnerName = new GridBagConstraints(); @@ -204,7 +188,7 @@ public class ChatWindow extends JFrame { gbc_partnerName.gridx = 1; gbc_partnerName.gridy = 0; - gbc_partnerName.insets = new Insets(0, 10, 0, 10); + gbc_partnerName.insets = new Insets(space, space, space, space); contentPane.add(textPane, gbc_partnerName); userList.setCellRenderer(new UserListRenderer()); @@ -234,20 +218,18 @@ public class ChatWindow extends JFrame { } }); - userList.setSelectionForeground(new Color(255, 255, 255)); - userList.setSelectionBackground(new Color(102, 0, 153)); - userList.setForeground(new Color(255, 255, 255)); - userList.setBackground(new Color(51, 51, 51)); userList.setFont(new Font("Arial", Font.PLAIN, 17)); - userList.setBorder(new EmptyBorder(5, 5, 5, 5)); + userList.setBorder(new EmptyBorder(space, space, space, space)); GridBagConstraints gbc_userList = new GridBagConstraints(); gbc_userList.fill = GridBagConstraints.VERTICAL; gbc_userList.gridx = 0; gbc_userList.gridy = 1; gbc_userList.anchor = GridBagConstraints.PAGE_START; - gbc_userList.insets = new Insets(0, 0, 10, 0); + gbc_userList.insets = new Insets(space, space, space, space); + changeChatWindowColors(); + contentPane.add(userList, gbc_userList); contentPane.revalidate(); @@ -257,6 +239,46 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); } + /** + * Used to immediately reload the ChatWindow when settings were changed. + * + * @since Envoy v0.1-alpha + */ + public void changeChatWindowColors() { + uiColors.setDisplayMode(settings.isDarkMode()); + + // contentPane + contentPane.setBackground(uiColors.getBackgroundColor()); + contentPane.setForeground(uiColors.getTextColor()); + // messageList + messageList.setSelectionForeground(uiColors.getTextColor()); + messageList.setSelectionBackground(uiColors.getSpecialUseColor()); + messageList.setForeground(uiColors.getTextColor()); + messageList.setBackground(uiColors.getUserInteractionColor()); + // scrollPane + scrollPane.setForeground(uiColors.getBackgroundColor()); + scrollPane.setBackground(uiColors.getUserInteractionColor()); + // messageEnterTextArea + messageEnterTextArea.setCaretColor(uiColors.getTextColor()); + messageEnterTextArea.setForeground(uiColors.getTextColor()); + messageEnterTextArea.setBackground(uiColors.getUserInteractionColor()); + // postButton + postButton.setForeground(uiColors.getTextColor()); + postButton.setBackground(uiColors.getSpecialUseColor()); + // settingsButton + settingsButton.setForeground(uiColors.getTextColor()); + settingsButton.setBackground(uiColors.getSpecialUseColor()); + // textPane + textPane.setBackground(uiColors.getBackgroundColor()); + textPane.setForeground(uiColors.getTextColor()); + // userList + userList.setSelectionForeground(uiColors.getTextColor()); + userList.setSelectionBackground(uiColors.getSpecialUseColor()); + userList.setForeground(uiColors.getTextColor()); + userList.setBackground(uiColors.getUserInteractionColor()); + + } + private void postMessage(JList messageList) { if (!client.hasRecipient()) { JOptionPane.showMessageDialog(this, @@ -268,7 +290,7 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient()); + final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient().getID()); localDB.addWaitingMessageToLocalDB(message, currentChat); messageList.setModel(currentChat.getModel()); diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index 7d5de28..4198648 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -1,15 +1,22 @@ package envoy.client.ui; import java.awt.BorderLayout; -import java.awt.Color; import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; import javax.swing.JButton; import javax.swing.JDialog; +import javax.swing.JOptionPane;//TODO: temporary import javax.swing.JPanel; import javax.swing.border.EmptyBorder; +import envoy.client.Settings; + /** + * This class provides the GUI to change the user specific settings. + * * Project: envoy-client
* File: SettingsScreen.java
* Created: 31 Oct 2019
@@ -18,139 +25,109 @@ import javax.swing.border.EmptyBorder; */ public class SettingsScreen extends JDialog { - private static final long serialVersionUID = -4476913491263077107L; - private final JPanel contentPanel = new JPanel(); - public static boolean enterToSend = true; + private static final long serialVersionUID = -4476913491263077107L; + private final JPanel contentPanel = new JPanel(); + private JPanel buttonPane = new JPanel(); + private JButton okButton = new JButton("Save"); + private JButton cancelButton = new JButton("Cancel"); + private static Settings settings; + private static UIColors uiColors; + private static int space = 5; + private static SettingsScreen settingsScreen; // TODO: Add a JPanel with all the Information necessary: // change (Picture,Username, Email, Password) and toggle(light/dark mode, // "ctrl+enter"/"enter" // to send a message directly) + /** - * Open the Settings screen. - * Only suited for Dev/Error mode. - * Avoid usage. + * Opens the settings screen.
* * @since Envoy v0.1-alpha */ - public static void open() { open(new SettingsScreen()); } + public static void open() { - /** - * Opens the Settings screen.
- * Use preferably since everyone is already initialised.
- * It personalises the screen more. - * - * @param username The name of the User - * @param Email The Email that is associated with that Account - * @since Envoy v0.1-alpha - */ - public static void open(String username) {// , String Email) {AUSKLAMMERN, WENN ANMELDUNG PER - // EMAIL IMPLEMENTIERT IST! - open(new SettingsScreen(username)); - } - - public static void open(SettingsScreen dialog) { - dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - dialog.setModal(true); - dialog.setVisible(true); + settings = Settings.getInstance(); + uiColors.setDisplayMode(settings.isDarkMode()); + settingsScreen = new SettingsScreen(); + settingsScreen.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + settingsScreen.setModal(true); + settingsScreen.setVisible(true); } /** - * Builds the Settings screen.
- * Use only as Dev/Error Mode.
- * Avoid usage. + * Builds the settings screen.
* * @since Envoy v0.1-alpha */ - public SettingsScreen() { - setBackground(Color.BLACK); + private SettingsScreen() { + setBounds(100, 100, 450, 300); getContentPane().setLayout(new BorderLayout()); - contentPanel.setBackground(Color.BLACK); - contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); - getContentPane().add(contentPanel, BorderLayout.CENTER); - contentPanel.setLayout(new BorderLayout(0, 0)); - { - JPanel buttonPane = new JPanel(); - buttonPane.setBackground(Color.BLACK); - getContentPane().add(buttonPane, BorderLayout.SOUTH); - buttonPane.setLayout(new BorderLayout(0, 0)); - { - JButton okButton = new JButton("Save"); - okButton.setActionCommand("OK"); - buttonPane.add(okButton, BorderLayout.EAST); - getRootPane().setDefaultButton(okButton); - okButton.addActionListener((evt) -> { - // Hier später die Daten abspeichern, wenn Datenmodell implementiert ist - dispose(); - }); - } - { - JButton cancelButton = new JButton("Cancel"); - cancelButton.setActionCommand("Cancel"); - buttonPane.add(cancelButton, BorderLayout.WEST); - - cancelButton.addActionListener((evt) -> { dispose(); }); - } - } - } - - /** - * Builds the Settings screen.
- * Use preferreably since everyone is already initialised.
- * It personalises the screen more. - * - * @param Username The name of the User - * @param Email The Email that is associated with that Account - * @since Envoy v0.1-alpha - */ - public SettingsScreen(String Username) {// , String Email, String hashedPwd) {AUSKLAMMERN, WENN ANMELDUNG PER EMAIL - // IMPLEMENTIERT IST! - setBackground(Color.BLACK); - setBounds(100, 100, 450, 300); - getContentPane().setLayout(new BorderLayout()); - contentPanel.setBackground(Color.BLACK); contentPanel.setLayout(new FlowLayout()); - contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + contentPanel.setBorder(new EmptyBorder(space, space, space, space)); getContentPane().add(contentPanel, BorderLayout.CENTER); { - JPanel buttonPane = new JPanel(); - buttonPane.setBackground(Color.BLACK); getContentPane().add(buttonPane, BorderLayout.SOUTH); - buttonPane.setLayout(new BorderLayout(0, 0)); + GridBagLayout gbl_buttonPane = new GridBagLayout(); + gbl_buttonPane.columnWidths = new int[] { 100, 250, 100, 0 }; + gbl_buttonPane.rowHeights = new int[] { 25, 0 }; + gbl_buttonPane.columnWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE }; + gbl_buttonPane.rowWeights = new double[] { 0.0, Double.MIN_VALUE }; + buttonPane.setLayout(gbl_buttonPane); { - JButton okButton = new JButton("Save"); - okButton.setActionCommand("OK"); - buttonPane.add(okButton, BorderLayout.EAST); - getRootPane().setDefaultButton(okButton); - okButton.addActionListener((evt) -> { - // Hier später die Daten abspeichern, wenn Datenmodell implementiert ist - dispose(); - }); - } - { - JButton cancelButton = new JButton("Cancel"); cancelButton.setActionCommand("Cancel"); - buttonPane.add(cancelButton, BorderLayout.WEST); + GridBagConstraints gbc_cancelButton = new GridBagConstraints(); + gbc_cancelButton.anchor = GridBagConstraints.NORTHWEST; + gbc_cancelButton.insets = new Insets(space, space, space, space); + gbc_cancelButton.gridx = 0; + gbc_cancelButton.gridy = 0; + buttonPane.add(cancelButton, gbc_cancelButton); cancelButton.addActionListener((evt) -> { dispose(); }); } + { + okButton.setActionCommand("OK"); + GridBagConstraints gbc_okButton = new GridBagConstraints(); + gbc_okButton.anchor = GridBagConstraints.NORTHEAST; + gbc_okButton.fill = GridBagConstraints.EAST; + gbc_okButton.insets = new Insets(space, space, space, space); + gbc_okButton.gridx = 2; + gbc_okButton.gridy = 0; + buttonPane.add(okButton, gbc_okButton); + getRootPane().setDefaultButton(okButton); + okButton.addActionListener((evt) -> { + try { + settings.setUsername(settings.getUsername());// still temporary value + settings.setEmail(settings.getEmail());// still temporary value + settings.setDarkMode(false);// TODO temporary values while no UI is implemented + settings.setEnterToSend(settings.isEnterToSend());// still temporary value + settings.save(); + } catch (Exception e) { + System.err.println("Something went wrong when changing the setting"); + settingsScreen.dispose(); + } + JOptionPane.showConfirmDialog(settingsScreen, "Successfully changed settings"); + }); + } } + changeSettingsScreenColors(); } - /** - * @return true if Enter should be used to send a message instead of ctrl+enter - * @since Envoy v0.1-alpha - */ - public static boolean isEnterToSend() { return enterToSend; } + private void changeSettingsScreenColors() { + // whole JDialog + setBackground(uiColors.getBackgroundColor()); + // contentPanel + contentPanel.setBackground(uiColors.getBackgroundColor()); + // buttonPane + buttonPane.setBackground(uiColors.getBackgroundColor()); + // cancelButton + cancelButton.setBackground(uiColors.getSpecialUseColor()); + cancelButton.setForeground(uiColors.getTextColor()); + // okButton + okButton.setBackground(uiColors.getSpecialUseColor()); + okButton.setForeground(uiColors.getTextColor()); + + } - /** - * @param enterToSend
- * toggles whether a message should be sent via - *
- * buttonpress "enter" or "ctrl"+"enter" - * @since Envoy v0.1-alpha - */ - public static void setEnterToSend(boolean enterForSend) { enterToSend = enterForSend; } - // TODO: Should be changed to private, but later to avoid warnings } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index c3a3baa..a456d6e 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -9,6 +9,7 @@ import javax.swing.JOptionPane; import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; +import envoy.client.Settings; import envoy.exception.EnvoyException; /** @@ -60,10 +61,11 @@ public class Startup { "Local DB error", JOptionPane.WARNING_MESSAGE); } + Settings settings = Settings.getInstance();//TODO delete line EventQueue.invokeLater(() -> { try { - ChatWindow frame = new ChatWindow(client, localDB); + ChatWindow frame = new ChatWindow(client, localDB, settings); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/envoy/client/ui/UIColors.java b/src/main/java/envoy/client/ui/UIColors.java new file mode 100644 index 0000000..2959fa5 --- /dev/null +++ b/src/main/java/envoy/client/ui/UIColors.java @@ -0,0 +1,158 @@ +package envoy.client.ui; + +import java.awt.Color; + +/** + * This class stores the colors that are used in Envoy. + *
+ *
+ * Project: envoy-client
+ * File: EnvoyColors.java
+ * Created: 16 Nov 2019
+ * + * @author Leon Hofmeister + * @since Envoy v0.2-alpha + */ +public class UIColors { + + private UIColors() {} + + /** + * This color is used for the general background where no other elements + * overlap. + * + * @since Envoy v0.2-alpha + */ + private Color backgroundColor; + + /** + * This color is used as background for all areas where a user can interact with + * Envoy. + * (i.e. a JTextArea or JList) + * + * @since Envoy v0.2-alpha + */ + + private Color userInteractionColor; + + /** + * This color is used for any areas that need special attention. + * (i.e. highlighting a selected list column or a button background) + * + * @since Envoy v0.2-alpha + */ + private Color specialUseColor; + + /** + * This color is the color in which text will be displayed. + * + * @since Envoy v0.2-alpha + */ + private Color textColor; + + /** + * This object ensures that only one {@link UIColors} object exists. + * + * @since Envoy v0.2-alpha + */ + private static UIColors uIColors; + + /** + * This method is used to ensure that there is only one instance of EnvoyColors. + * + * @param darkMode default value how envoyColors should be displayed + * @return the instance of EnvoyColors + * @since Envoy v0.2-alpha + */ + public static UIColors getInstance(boolean darkMode) { + if (uIColors == null) { uIColors = new UIColors(); } + uIColors.setDisplayMode(darkMode); + return uIColors; + } + + /** + * Used to change the appearance of Envoy. + * + * @param darkMode if true, Envoy will be displayed in dark mode else it will + * use bright mode + * @since Envoy v0.2-alpha + */ + public void setDisplayMode(boolean darkMode) { + if (darkMode) { + uIColors.setBackgroundColor(Color.black); // TODO: other color suggestions? + uIColors.setUserInteractionColor(Color.darkGray); // temporary + uIColors.setSpecialUseColor(Color.blue); // temporary + uIColors.setTextColor(Color.white); // temporary + + } else { + uIColors.setBackgroundColor(Color.white); // temporary + uIColors.setUserInteractionColor(Color.lightGray); // temporary + uIColors.setSpecialUseColor(Color.green); // temporary + uIColors.setTextColor(Color.black); // temporary + + } + } + + /** + * @return the {@link UIColors#backgroundColor} + * @since Envoy v0.2-alpha + */ + public Color getBackgroundColor() { return backgroundColor; } + + /** + * @param backgroundColor the new {@link UIColors#backgroundColor} + * @since Envoy v0.2-alpha + */ + public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } + + /** + * @return the {@link UIColors#userInteractionColor} + * @since Envoy v0.2-alpha + */ + public Color getUserInteractionColor() { return userInteractionColor; } + + /** + * @param userInteractionColor the new {@link UIColors#userInteractionColor} + * @since Envoy v0.2-alpha + */ + public void setUserInteractionColor(Color userInteractionColor) { + this.userInteractionColor = userInteractionColor; + } + + /** + * @return the {@link UIColors#specialUseColor} + * @since Envoy v0.2-alpha + */ + public Color getSpecialUseColor() { return specialUseColor; } + + /** + * @param specialUseColor the new {@link UIColors#specialUseColor} + * @since Envoy v0.2-alpha + */ + public void setSpecialUseColor(Color specialUseColor) { this.specialUseColor = specialUseColor; } + + /** + * @return the {@link UIColors#textColor} + * @since Envoy v0.2-alpha + */ + public Color getTextColor() { return textColor; } + + /** + * @param textColor the new {@link UIColors#textColor} + * @since Envoy v0.2-alpha + */ + public void setTextColor(Color textColor) { this.textColor = textColor; } + + /** + * @return the {@link UIColors#uIColors} + * @since Envoy v0.2-alpha + */ + public static UIColors getEnvoyColors() { return uIColors; } + + @Deprecated + /** + * @param envoyColors the new {@link EnvoyColors#envoyColors} + * @since Envoy v0.2-alpha + */ + public static void setEnvoyColors(UIColors uIColors) { UIColors.uIColors = uIColors; } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index 40bb2ad..a0a2b4e 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -56,6 +56,12 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { status, name)); break; + case AFK: + break; + case DO_NOT_DISTURB: + break; + default: + break; } From 22a9fb7822fe5e49042da3fe232086e83ceafa6b Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 22 Nov 2019 22:40:00 +0100 Subject: [PATCH 067/474] improved Javadoc in some files, especially UIColors --- src/main/java/envoy/client/Client.java | 4 +- src/main/java/envoy/client/LocalDB.java | 2 +- src/main/java/envoy/client/ui/UIColors.java | 66 +++++---------------- 3 files changed, 20 insertions(+), 52 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 522d44f..6533d47 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -129,7 +129,9 @@ public class Client { * Updating UserStatus of all users in LocalDB. (Server sends all users with * their updated UserStatus to the client.)
* - * @param userId + * @param userId the client who sends the sync + * @param sync the sync object (yet to be converted from java class to sync.xml) + * @return a returnSync.xml file * @since Envoy v0.1-alpha */ public Sync sendSync(long userId, Sync sync) { diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 5b702e8..38f74e4 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -270,7 +270,7 @@ public class LocalDB { /** * Adds a user to the {@code sync} {@link Sync} object. * - * @param user + * @param user the user who should be added to the {@link Sync} object * @since Envoy v0.1-alpha */ public void addUserToSync(User user) { sync.getUsers().add(user); } diff --git a/src/main/java/envoy/client/ui/UIColors.java b/src/main/java/envoy/client/ui/UIColors.java index 2959fa5..e810250 100644 --- a/src/main/java/envoy/client/ui/UIColors.java +++ b/src/main/java/envoy/client/ui/UIColors.java @@ -17,44 +17,10 @@ public class UIColors { private UIColors() {} - /** - * This color is used for the general background where no other elements - * overlap. - * - * @since Envoy v0.2-alpha - */ private Color backgroundColor; - - /** - * This color is used as background for all areas where a user can interact with - * Envoy. - * (i.e. a JTextArea or JList) - * - * @since Envoy v0.2-alpha - */ - private Color userInteractionColor; - - /** - * This color is used for any areas that need special attention. - * (i.e. highlighting a selected list column or a button background) - * - * @since Envoy v0.2-alpha - */ private Color specialUseColor; - - /** - * This color is the color in which text will be displayed. - * - * @since Envoy v0.2-alpha - */ private Color textColor; - - /** - * This object ensures that only one {@link UIColors} object exists. - * - * @since Envoy v0.2-alpha - */ private static UIColors uIColors; /** @@ -94,25 +60,29 @@ public class UIColors { } /** - * @return the {@link UIColors#backgroundColor} + * @return the general background color where no other element overlaps * @since Envoy v0.2-alpha */ public Color getBackgroundColor() { return backgroundColor; } /** - * @param backgroundColor the new {@link UIColors#backgroundColor} + * @param backgroundColor the general background where no other element overlaps * @since Envoy v0.2-alpha */ public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } /** - * @return the {@link UIColors#userInteractionColor} + * @return the userInteractionColor:
+ * This color is used as background for all areas where a user can + * interact with Envoy (i.e. a JTextArea or JList) * @since Envoy v0.2-alpha */ public Color getUserInteractionColor() { return userInteractionColor; } /** - * @param userInteractionColor the new {@link UIColors#userInteractionColor} + * @param userInteractionColor This color is used as background for all areas
+ * where a user can interact with Envoy + * (i.e. a JTextArea or JList) * @since Envoy v0.2-alpha */ public void setUserInteractionColor(Color userInteractionColor) { @@ -120,39 +90,35 @@ public class UIColors { } /** - * @return the {@link UIColors#specialUseColor} + * @return specialUseColor: This color is used for any areas that need special attention.
+ * (i.e. highlighting a selected list column or a button background) * @since Envoy v0.2-alpha */ public Color getSpecialUseColor() { return specialUseColor; } /** - * @param specialUseColor the new {@link UIColors#specialUseColor} + * @param specialUseColor This color is used for any areas that need special attention.
+ * (i.e. highlighting a selected list column or a button background) * @since Envoy v0.2-alpha */ public void setSpecialUseColor(Color specialUseColor) { this.specialUseColor = specialUseColor; } /** - * @return the {@link UIColors#textColor} + * @return textColor: The color in which text will be displayed * @since Envoy v0.2-alpha */ public Color getTextColor() { return textColor; } /** - * @param textColor the new {@link UIColors#textColor} + * @param textColor The color in which text will be displayed * @since Envoy v0.2-alpha */ public void setTextColor(Color textColor) { this.textColor = textColor; } + @Deprecated /** - * @return the {@link UIColors#uIColors} + * @return the uiColors object * @since Envoy v0.2-alpha */ public static UIColors getEnvoyColors() { return uIColors; } - - @Deprecated - /** - * @param envoyColors the new {@link EnvoyColors#envoyColors} - * @since Envoy v0.2-alpha - */ - public static void setEnvoyColors(UIColors uIColors) { UIColors.uIColors = uIColors; } } \ No newline at end of file From ddc6e27abb25f98a3876610ab31c1f247cac3046 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 23 Nov 2019 13:25:12 +0100 Subject: [PATCH 068/474] Added settings object and light theme Improvements: * settings are implemented via Preferences API * fixed "bug" that made partner name pane editable * light theme is added as new display method --- src/main/java/envoy/client/Settings.java | 11 +++++- src/main/java/envoy/client/ui/ChatWindow.java | 16 ++++---- .../java/envoy/client/ui/SettingsScreen.java | 39 ++++++++++--------- src/main/java/envoy/client/ui/Startup.java | 6 +-- src/main/java/envoy/client/ui/UIColors.java | 3 +- 5 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 7377876..76d8ce3 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -2,6 +2,8 @@ package envoy.client; import java.util.prefs.Preferences; +import envoy.schema.User; + /** * Project: envoy-client
* File: Settings.java
@@ -37,8 +39,8 @@ public class Settings { public static Settings getInstance() { if (settings == null) { settings = new Settings(); + settings.load(); } - settings.load(); return settings; } @@ -55,6 +57,13 @@ public class Settings { prefs.putBoolean("darkMode", settings.isDarkMode()); prefs.putBoolean("enterToSend", settings.isEnterToSend()); } + + public void firstSave(User user) { + prefs.put("username", user.getName()); +// prefs.put("email", user.getEmail()); +// prefs.putBoolean("darkMode", true); +// prefs.putBoolean("enterToSend", true); + } /** * @return the username diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 7d5166d..38634ea 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -51,7 +51,6 @@ public class ChatWindow extends JFrame { // user specific objects private Client client; private LocalDB localDB; - private Settings settings; // used colors in Envoy private UIColors uiColors = UIColors.getInstance(true); // GUI components @@ -63,15 +62,14 @@ public class ChatWindow extends JFrame { private JScrollPane scrollPane = new JScrollPane(); private JTextPane textPane = new JTextPane(); // private JCheckBox jCbChangeMode; - private JButton postButton = new JButton(); - private JButton settingsButton = new JButton(); + private JButton postButton = new JButton("Post"); + private JButton settingsButton = new JButton("Settings"); private static int space = 4; - public ChatWindow(Client client, LocalDB localDB, Settings setting) { + public ChatWindow(Client client, LocalDB localDB) { this.client = client; this.localDB = localDB; - this.settings = setting; setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); @@ -119,7 +117,6 @@ public class ChatWindow extends JFrame { gbc_scrollPane.gridy = 1; gbc_scrollPane.insets = new Insets(space, space, space, space); - contentPane.add(scrollPane, gbc_scrollPane); // Message enter field @@ -128,7 +125,7 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER && ((settings.isEnterToSend() && e.getModifiersEx() == 0) + if (e.getKeyCode() == KeyEvent.VK_ENTER && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); @@ -179,6 +176,7 @@ public class ChatWindow extends JFrame { settingsButton.addActionListener((evt) -> { try { SettingsScreen.open(); + changeChatWindowColors(); } catch (Exception e) { System.err.println("An error occured while opening the settings screen: " + e); e.printStackTrace(); @@ -188,6 +186,7 @@ public class ChatWindow extends JFrame { // Partner name display textPane.setFont(new Font("Arial", Font.PLAIN, 20)); + textPane.setEditable(false); GridBagConstraints gbc_partnerName = new GridBagConstraints(); gbc_partnerName.fill = GridBagConstraints.HORIZONTAL; @@ -216,7 +215,6 @@ public class ChatWindow extends JFrame { readCurrentChat(); client.setRecipient(user); - textPane.setText(currentChat.getRecipient().getName()); messageList.setModel(currentChat.getModel()); @@ -251,7 +249,7 @@ public class ChatWindow extends JFrame { * @since Envoy v0.1-alpha */ public void changeChatWindowColors() { - uiColors.setDisplayMode(settings.isDarkMode()); + uiColors.setDisplayMode(Settings.getInstance().isDarkMode()); // contentPane contentPane.setBackground(uiColors.getBackgroundColor()); diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index 4198648..56730aa 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -8,7 +8,6 @@ import java.awt.Insets; import javax.swing.JButton; import javax.swing.JDialog; -import javax.swing.JOptionPane;//TODO: temporary import javax.swing.JPanel; import javax.swing.border.EmptyBorder; @@ -30,8 +29,6 @@ public class SettingsScreen extends JDialog { private JPanel buttonPane = new JPanel(); private JButton okButton = new JButton("Save"); private JButton cancelButton = new JButton("Cancel"); - private static Settings settings; - private static UIColors uiColors; private static int space = 5; private static SettingsScreen settingsScreen; @@ -47,8 +44,7 @@ public class SettingsScreen extends JDialog { */ public static void open() { - settings = Settings.getInstance(); - uiColors.setDisplayMode(settings.isDarkMode()); + UIColors.getInstance(Settings.getInstance().isDarkMode()); settingsScreen = new SettingsScreen(); settingsScreen.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); settingsScreen.setModal(true); @@ -98,16 +94,23 @@ public class SettingsScreen extends JDialog { getRootPane().setDefaultButton(okButton); okButton.addActionListener((evt) -> { try { - settings.setUsername(settings.getUsername());// still temporary value - settings.setEmail(settings.getEmail());// still temporary value - settings.setDarkMode(false);// TODO temporary values while no UI is implemented - settings.setEnterToSend(settings.isEnterToSend());// still temporary value - settings.save(); + Settings.getInstance().setUsername(Settings.getInstance().getUsername());// still temporary + // value + Settings.getInstance().setEmail(Settings.getInstance().getEmail());// still temporary value + Settings.getInstance().setDarkMode(!Settings.getInstance().isDarkMode());// TODO temporary + // values while no + // UI is implemented + Settings.getInstance().setEnterToSend(Settings.getInstance().isEnterToSend());// still temporary + // value + Settings.getInstance().save(); + UIColors.getUIColors().setDisplayMode(Settings.getInstance().isDarkMode()); + changeSettingsScreenColors(); + revalidate(); + repaint(); } catch (Exception e) { System.err.println("Something went wrong when changing the setting"); settingsScreen.dispose(); } - JOptionPane.showConfirmDialog(settingsScreen, "Successfully changed settings"); }); } } @@ -116,17 +119,17 @@ public class SettingsScreen extends JDialog { private void changeSettingsScreenColors() { // whole JDialog - setBackground(uiColors.getBackgroundColor()); + setBackground(UIColors.getUIColors().getBackgroundColor()); // contentPanel - contentPanel.setBackground(uiColors.getBackgroundColor()); + contentPanel.setBackground(UIColors.getUIColors().getBackgroundColor()); // buttonPane - buttonPane.setBackground(uiColors.getBackgroundColor()); + buttonPane.setBackground(UIColors.getUIColors().getBackgroundColor()); // cancelButton - cancelButton.setBackground(uiColors.getSpecialUseColor()); - cancelButton.setForeground(uiColors.getTextColor()); + cancelButton.setBackground(UIColors.getUIColors().getSpecialUseColor()); + cancelButton.setForeground(UIColors.getUIColors().getTextColor()); // okButton - okButton.setBackground(uiColors.getSpecialUseColor()); - okButton.setForeground(uiColors.getTextColor()); + okButton.setBackground(UIColors.getUIColors().getSpecialUseColor()); + okButton.setForeground(UIColors.getUIColors().getTextColor()); } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index a456d6e..2781a8a 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -61,11 +61,11 @@ public class Startup { "Local DB error", JOptionPane.WARNING_MESSAGE); } - Settings settings = Settings.getInstance();//TODO delete line - + Settings.getInstance().firstSave(client.getSender()); + EventQueue.invokeLater(() -> { try { - ChatWindow frame = new ChatWindow(client, localDB, settings); + ChatWindow frame = new ChatWindow(client, localDB); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/envoy/client/ui/UIColors.java b/src/main/java/envoy/client/ui/UIColors.java index e810250..fdad862 100644 --- a/src/main/java/envoy/client/ui/UIColors.java +++ b/src/main/java/envoy/client/ui/UIColors.java @@ -115,10 +115,9 @@ public class UIColors { */ public void setTextColor(Color textColor) { this.textColor = textColor; } - @Deprecated /** * @return the uiColors object * @since Envoy v0.2-alpha */ - public static UIColors getEnvoyColors() { return uIColors; } + public static UIColors getUIColors() { return uIColors; } } \ No newline at end of file From d09432cecf90cdd81d233e05f642ac3d249b1532 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 27 Nov 2019 06:30:05 +0100 Subject: [PATCH 069/474] Envoy Client v0.1-alpha --- .classpath | 32 ++ .gitignore | 2 + .project | 40 ++ .settings/org.eclipse.core.resources.prefs | 6 + .settings/org.eclipse.jdt.core.prefs | 8 + .settings/org.eclipse.m2e.core.prefs | 4 + pom.xml | 41 ++ src/main/java/envoy/client/Chat.java | 45 +++ src/main/java/envoy/client/Client.java | 179 +++++++++ src/main/java/envoy/client/Config.java | 127 +++++++ src/main/java/envoy/client/LocalDB.java | 293 +++++++++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 349 ++++++++++++++++++ .../envoy/client/ui/MessageListRenderer.java | 54 +++ .../java/envoy/client/ui/SettingsScreen.java | 156 ++++++++ src/main/java/envoy/client/ui/Startup.java | 73 ++++ .../envoy/client/ui/UserListRenderer.java | 65 ++++ src/main/resources/client.properties | 3 + 17 files changed, 1477 insertions(+) create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 pom.xml create mode 100644 src/main/java/envoy/client/Chat.java create mode 100644 src/main/java/envoy/client/Client.java create mode 100644 src/main/java/envoy/client/Config.java create mode 100644 src/main/java/envoy/client/LocalDB.java create mode 100644 src/main/java/envoy/client/ui/ChatWindow.java create mode 100644 src/main/java/envoy/client/ui/MessageListRenderer.java create mode 100644 src/main/java/envoy/client/ui/SettingsScreen.java create mode 100644 src/main/java/envoy/client/ui/Startup.java create mode 100644 src/main/java/envoy/client/ui/UserListRenderer.java create mode 100644 src/main/resources/client.properties diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..906bfce --- /dev/null +++ b/.classpath @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e12b13a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target/ +/localDB/ \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..08d7599 --- /dev/null +++ b/.project @@ -0,0 +1,40 @@ + + + envoy-client + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.jboss.tools.jst.web.kb.kbbuilder + + + + + org.jboss.tools.cdi.core.cdibuilder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.jboss.tools.jst.web.kb.kbnature + org.jboss.tools.cdi.core.cdinature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..04cfa2c --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..cb635b1 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..14b697b --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d688c37 --- /dev/null +++ b/pom.xml @@ -0,0 +1,41 @@ + + 4.0.0 + + informatik-ag-ngl + envoy-client + 0.0.1-SNAPSHOT + + Envoy Client + https://github.com/informatik-ag-ngl/envoy-client + + + UTF-8 + UTF-8 + 1.8 + 1.8 + + + + + org.jboss.resteasy + resteasy-client + 4.1.1.Final + + + org.jboss.resteasy + resteasy-jaxb-provider + 4.3.1.Final + + + informatik-ag-ngl + envoy-common + 0.0.1-SNAPSHOT + + + + + envoy-client + + \ No newline at end of file diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java new file mode 100644 index 0000000..da35bd3 --- /dev/null +++ b/src/main/java/envoy/client/Chat.java @@ -0,0 +1,45 @@ +package envoy.client; + +import java.io.Serializable; + +import javax.swing.DefaultListModel; + +import envoy.schema.Message; +import envoy.schema.User; + +public class Chat implements Serializable { + + private static final long serialVersionUID = -7751248474547242056L; + + private User recipient; + private DefaultListModel model = new DefaultListModel<>(); + + /** + * Provides the list of messages that the recipient receives.
+ * Saves the Messages in the corresponding chat at that Point. + * + * @param recipient the user who receives the messages + * @since Envoy v0.1-alpha + */ + public Chat(User recipient) { this.recipient = recipient; } + + /** + * @return the recipient of a message + * @since Envoy v0.1-alpha + */ + public User getRecipient() { return recipient; } + + /** + * Adds the received message at the current Point in the current chat + * + * @param message the message to add in said chat + * @since Envoy v0.1-alpha + */ + public void appendMessage(Message message) { model.addElement(message); } + + /** + * @return all messages in the current chat + * @since Envoy v0.1-alpha + */ + public DefaultListModel getModel() { return model; } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java new file mode 100644 index 0000000..522d44f --- /dev/null +++ b/src/main/java/envoy/client/Client.java @@ -0,0 +1,179 @@ +package envoy.client; + +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; + +import envoy.schema.ObjectFactory; +import envoy.schema.Sync; +import envoy.schema.User; + +/** + * Project: envoy-client
+ * File: Client.java
+ * Created: 28 Sep 2019
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @author Leon Hofmeister + * @since Envoy v0.1-alpha + */ +public class Client { + + private ObjectFactory objectFactory = new ObjectFactory(); + private Config config; + private User sender, recipient; + + public Client(Config config, String username) { + this.config = config; + sender = getUser(username); + System.out.println("ID: " + sender.getID()); + } + + private R post(String uri, T body, Class responseBodyClass) { + javax.ws.rs.client.Client client = ClientBuilder.newClient(); + WebTarget target = client.target(uri); + + Response response = target.request().post(Entity.entity(body, "application/xml")); + R responseBody = response.readEntity(responseBodyClass); + response.close(); + client.close(); + + return responseBody; + + } + + /** + * Returns a {@link Sync} with all users on the server. + * + * @return Sync - List of all users on the server. + * @since Envoy v0.1-alpha + */ + public Sync getUsersListXml() { + Sync sendSync = objectFactory.createSync(); + User user = objectFactory.createUser(); + user.setID(-1); + sendSync.getUsers().add(user); + + Sync returnSendSync = post( + String + .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + sendSync, + Sync.class); + return returnSendSync; + + } + + /** + * Returns a {@link User} with a specific id by name. + * + * @param name - the name of the {@link User} + * @return a {@link User} with the specified name + * @since Envoy v0.1-alpha + */ + private User getUser(String name) { + Sync senderSync = objectFactory.createSync(); + User user = objectFactory.createUser(); + user.setName(name); + senderSync.getUsers().add(user); + + Sync returnSenderSync = post( + String + .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + senderSync, + Sync.class); + + User returnSender = objectFactory.createUser(); + + if (returnSenderSync.getUsers().size() == 1) { + returnSender = returnSenderSync.getUsers().get(0); + } else { + System.out.println("ERROR exiting..."); + } + + return returnSender; + } + + /** + * Sends the "sync" Sync Object to the server and gets a "returnSync" Sync + * Object as response.
+ * It is also used to get the own sender at the start of the client + * (Client sends "sync" Sync Object with single user in it(name: the name + * entered at login, id: 0, UserStatus:null))
+ * and to get a complete list of all users saved on the server. + * (Client sends "sync" Sync Object with single user in it(name: "" (empty), id: + * -1, UserStatus:null))
+ * This method also processes the response Sync Object.
+ * It sorts its users and messages by specific variables and does certain things + * with them.
+ *
+ * Messages:
+ * -State SENT: Update Local message(s) with State WAITING (add Message ID and + * change State to SENT). (server sends these informations to the client if + * message(s) with State WAITING were successfully sent to the server)
+ * -State RECEIVED, SenderID != 0: Adds the unread Messages returned from the + * server in the latest sync to the "unreadMessagesSync" Sync Object.
+ * -State RECEIVED, SenderID == 0: Update message(s) in localDB to state + * RECEIVED. + * (server sends these informations to the client if the other client received + * the message(s).)
+ * -State READ: Update message(s) in the LocalDB to state READ. (server sends + * these informations to the client if the other client read + * the message(s).)
+ *
+ * Users:
+ * Updating UserStatus of all users in LocalDB. (Server sends all users with + * their updated UserStatus to the client.)
+ * + * @param userId + * @since Envoy v0.1-alpha + */ + public Sync sendSync(long userId, Sync sync) { + // Print sync XML to console + JAXBContext jc; + try { + jc = JAXBContext.newInstance("envoy.schema"); + Marshaller m = jc.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.marshal(sync, System.out); + } catch (JAXBException e) { + e.printStackTrace(); + } + + // Send sync + return post(String + .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), + sync, + Sync.class); + } + + /** + * @return the sender object that represents this client. + * @since Envoy v0.1-alpha + */ + public User getSender() { return sender; } + + /** + * @return the current recipient of the current chat. + * @since Envoy v0.1-alpha + */ + public User getRecipient() { return recipient; } + + /** + * Sets the recipient. + * @param recipient - the recipient to set + * @since Envoy v0.1-alpha + */ + public void setRecipient(User recipient) { this.recipient = recipient; } + + /** + * @return true, if a recipient is selected + * @since Envoy v0.1-alpha + */ + public boolean hasRecipient() { return recipient != null; } +} + diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java new file mode 100644 index 0000000..c31c972 --- /dev/null +++ b/src/main/java/envoy/client/Config.java @@ -0,0 +1,127 @@ +package envoy.client; + +import java.io.File; +import java.util.Properties; + +/** + * Project: envoy-client
+ * File: Config.java
+ * Created: 12 Oct 2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.1-alpha + */ +public class Config { + + private String server; + private int port; + private File localDB; + private int syncTimeout; + + private static Config config; + + private Config() {} + + public static Config getInstance() { + if (config == null) config = new Config(); + return config; + } + + /** + * Defaults to the {@code client.properties} file for information. + * + * @param properties a {@link Properties} object containing information about + * the server and port, as well as the path to the local + * database + * @since Envoy v0.1-alpha + */ + public void load(Properties properties) { + if (properties.containsKey("server")) server = properties.getProperty("server"); + if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); + localDB = new File(properties.getProperty("localDB", ".\\localDB")); + syncTimeout = Integer.parseInt(properties.getProperty("syncTimeout", "1000")); + } + + /** + * Sets the server, port and localDB path via command line properties --server / + * -s, --port / -p and --localDB / -db. + * + * @param args the command line arguments to parse + * @since Envoy v0.1-alpha + */ + public void load(String[] args) { + for (int i = 0; i < args.length; i++) + switch (args[i]) { + case "--server": + case "-s": + server = args[++i]; + break; + case "--port": + case "-p": + port = Integer.parseInt(args[++i]); + break; + case "--localDB": + case "-db": + localDB = new File(args[++i]); + } + if (localDB == null) localDB = new File(".\\localDB"); + if (syncTimeout == 0) syncTimeout = 1000; + } + + /** + * @return {@code true} if server, port and localDB directory are known. + * @since Envoy v0.1-alpha + */ + public boolean isInitialized() { + return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; + } + + /** + * @return the host name of the Envoy server + * @since Envoy v0.1-alpha + */ + public String getServer() { return server; } + + /** + * Changes the default server host name. + * Exclusively intended for development purposes. + * + * @param server the host name of the Envoy server + * @since Envoy v0.1-alpha + */ + public void setServer(String server) { this.server = server; } + + /** + * @return the port at which the Envoy server is located on the host + * @since Envoy v0.1-alpha + */ + public int getPort() { return port; } + + /** + * Changes the default port. + * Exclusively intended for development purposes. + * + * @param port the port where an Envoy server is located + * @since Envoy v0.1-alpha + */ + public void setPort(int port) { this.port = port; } + + /** + * @return the local database specific to the client user + * @since Envoy v0.1-alpha + **/ + public File getLocalDB() { return localDB; } + + /** + * Changes the default local database. + * Exclusively intended for development purposes. + * + * @param the file containing the local database + * @since Envoy v0.1-alpha + **/ + public void setLocalDB(File localDB) { this.localDB = localDB; } + + public int getSyncTimeout() { return syncTimeout; } + + public void setSyncTimeout(int syncTimeout) { this.syncTimeout = syncTimeout; } +} diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java new file mode 100644 index 0000000..3cc96a2 --- /dev/null +++ b/src/main/java/envoy/client/LocalDB.java @@ -0,0 +1,293 @@ +package envoy.client; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; + +import envoy.exception.EnvoyException; +import envoy.schema.Message; +import envoy.schema.Message.Metadata.MessageState; +import envoy.schema.ObjectFactory; +import envoy.schema.Sync; +import envoy.schema.User; + +/** + * Project: envoy-client
+ * File: LocalDB.java
+ * Created: 27.10.2019
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.1-alpha + */ +public class LocalDB { + + private File localDB; + private User sender; + private List chats = new ArrayList<>(); + private ObjectFactory objectFactory = new ObjectFactory(); + private DatatypeFactory datatypeFactory; + + private Sync unreadMessagesSync = objectFactory.createSync(); + private Sync sync = objectFactory.createSync(); + private Sync readMessages = objectFactory.createSync(); + + /** + * Constructs an empty local database. + * + * @param client the user that is logged in with this client + * @since Envoy v0.1-alpha + */ + + public LocalDB(User sender) { + this.sender = sender; + try { + datatypeFactory = DatatypeFactory.newInstance(); + } catch (DatatypeConfigurationException e) { + e.printStackTrace(); + } + } + + /** + * Initializes the local database and fills it with values + * if the user has already sent or received messages. + * + * @param localDBDir the directory where we wish to save/load the database from. + * @throws EnvoyException if the directory selected is not an actual directory. + * @since Envoy v0.1-alpha + */ + public void initializeDBFile(File localDBDir) throws EnvoyException { + if (localDBDir.exists() && !localDBDir.isDirectory()) + throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); + localDB = new File(localDBDir, sender.getID() + ".db"); + if (localDB.exists()) loadFromLocalDB(); + } + + /** + * Saves the database into a file for future use. + * + * @throws IOException if something went wrong during saving + * @since Envoy v0.1-alpha + */ + public void saveToLocalDB() { + try { + localDB.getParentFile().mkdirs(); + localDB.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("unable to save the messages"); + } + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) { + out.writeObject(chats); + } catch (IOException ex) { + ex.printStackTrace(); + System.err.println("unable to save the messages"); + } + } + + /** + * Loads all chats saved by Envoy for the client user. + * + * @throws EnvoyException if something fails while loading. + * @since Envoy v0.1-alpha + */ + @SuppressWarnings("unchecked") + private void loadFromLocalDB() throws EnvoyException { + try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(localDB))) { + Object obj = in.readObject(); + if (obj instanceof ArrayList) chats = (ArrayList) obj; + } catch (ClassNotFoundException | IOException e) { + throw new EnvoyException(e); + } + } + + /** + * Creates a {@link Message} object serializable to XML. + * + * @param textContent The content (text) of the message + * @return prepared {@link Message} object + */ + public Message createMessage(String textContent, User recipient) { + Message.Metadata metaData = objectFactory.createMessageMetadata(); + metaData.setSender(sender.getID()); + metaData.setRecipient(recipient.getID()); + metaData.setState(MessageState.WAITING); + metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); + + Message.Content content = objectFactory.createMessageContent(); + content.setType("text"); + content.setText(textContent); + + Message message = objectFactory.createMessage(); + message.setMetadata(metaData); + message.getContent().add(content); + + return message; + } + + public Sync fillSync(long userId) { + addWaitingMessagesToSync(); + + sync.getMessages().addAll(readMessages.getMessages()); + readMessages.getMessages().clear(); + + System.out.println(sync.getMessages().size()); + return sync; + } + + public void applySync(Sync returnSync) { + for (int i = 0; i < returnSync.getMessages().size(); i++) { + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.SENT) { + // Update Local Messages with State WAITING (add Message ID and change State to + // SENT) + for (int j = 0; j < sync.getMessages().size(); j++) { + if (j == i) { + sync.getMessages().get(j).getMetadata().setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId()); + sync.getMessages().get(j).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState()); + } + } + } + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { + // these are the unread Messages from the server + unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); + } + + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() == 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { + // Update Messages in localDB to state RECEIVED + for (int j = 0; j < getChats().size(); j++) { + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() + .get(i) + .getMetadata() + .getMessageId()) { + // Update Message in LocalDB + getChats().get(j).getModel().get(k).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState()); + } + } + } + } + + } + + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) { + // Update local Messages to state READ + System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + + "was initialized to be set to READ in localDB."); + for (int j = 0; j < getChats().size(); j++) { + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); + for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() + .get(i) + .getMetadata() + .getMessageId()) { + System.out.println( + "Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + "was selected."); + getChats().get(j).getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + System.out + .println("Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); + } + } + } + } + } + } + + // Updating UserStatus of all users in LocalDB + for (int j = 0; j < returnSync.getUsers().size(); j++) { + for (int k = 0; k < getChats().size(); k++) { + if (getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) { + + getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus()); + System.out.println(getChats().get(k).getRecipient().getStatus().toString()); + } + } + } + + sync.getMessages().clear(); + sync.getUsers().clear(); + } + + /** + * Adds the unread messages returned from the server in the latest sync to the + * right chats in the LocalDB. + * + * @param localDB + * @since Envoy v0.1-alpha + */ + public void addUnreadMessagesToLocalDB() { + Sync unreadMessages = unreadMessagesSync; + for (int i = 0; i < unreadMessages.getMessages().size(); i++) + for (int j = 0; j < getChats().size(); j++) + if (getChats().get(j).getRecipient().getID() == unreadMessages.getMessages().get(i).getMetadata().getSender()) { + getChats().get(j).appendMessage(unreadMessages.getMessages().get(i)); + } + } + + /** + * Changes all messages with state {@code RECEIVED} of a specific chat to state + * {@code READ}. + *
+ * Adds these messages to the {@code readMessages} {@link Sync} object. + * + * @param currentChat + * @since Envoy v0.1-alpha + */ + public void setMessagesToRead(Chat currentChat) { + for (int i = currentChat.getModel().size() - 1; i >= 0; --i) + if (currentChat.getModel().get(i).getMetadata().getRecipient() != currentChat.getRecipient().getID()) + if (currentChat.getModel().get(i).getMetadata().getState() == MessageState.RECEIVED) { + currentChat.getModel().get(i).getMetadata().setState(MessageState.READ); + readMessages.getMessages().add(currentChat.getModel().get(i)); + } else break; + } + + /** + * Adds all messages with state {@code WAITING} from the {@link LocalDB} to the + * {@link Sync} object. + * + * @since Envoy v0.1-alpha + */ + private void addWaitingMessagesToSync() { + for (Chat chat : getChats()) + for (int i = 0; i < chat.getModel().size(); i++) + if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) { + System.out.println("Got Waiting Message"); + sync.getMessages().add(chat.getModel().get(i)); + } + } + + /** + * Clears the {@code unreadMessagesSync} {@link Sync} object. + * + * @since Envoy v0.1-alpha + */ + public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } + + /** + * @return all saves {@link Chat} objects that list the client user as the + * client + * @since Envoy v0.1-alpha + **/ + public List getChats() { return chats; } + + /** + * @return the {@link User} who initialized the local database + * @since Envoy v0.1-alpha + */ + public User getUser() { return sender; } +} diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java new file mode 100644 index 0000000..32b024b --- /dev/null +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -0,0 +1,349 @@ +package envoy.client.ui; + +import java.awt.Color; +import java.awt.ComponentOrientation; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextPane; +import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.border.EmptyBorder; + +import envoy.client.Chat; +import envoy.client.Client; +import envoy.client.Config; +import envoy.client.LocalDB; +import envoy.schema.Message; +import envoy.schema.Sync; +import envoy.schema.User; + +/** + * Project: envoy-client
+ * File: ChatWindow.java
+ * Created: 28 Sep 2019
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @author Leon Hofmeister + * @since Envoy v0.1-alpha + */ +public class ChatWindow extends JFrame { + + private static final long serialVersionUID = 6865098428255463649L; + + private JPanel contentPane = new JPanel(); + + private Client client; + private LocalDB localDB; + + private JList userList = new JList<>(); + private Chat currentChat; + + private JTextArea messageEnterTextArea; + + public ChatWindow(Client client, LocalDB localDB) { + this.client = client; + this.localDB = localDB; + + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(100, 100, 600, 800); + setTitle("Envoy"); + setLocationRelativeTo(null); + + // Save chats when window closes + addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { localDB.saveToLocalDB(); } + }); + + contentPane.setBackground(new Color(0, 0, 0)); + contentPane.setForeground(Color.white); + contentPane.setBorder(new EmptyBorder(0, 5, 0, 0)); + setContentPane(contentPane); + GridBagLayout gbl_contentPane = new GridBagLayout(); + gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; + gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; + gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; + gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 }; + contentPane.setLayout(gbl_contentPane); + + JList messageList = new JList<>(); + messageList.setCellRenderer(new MessageListRenderer()); + + messageList.setFocusTraversalKeysEnabled(false); + messageList.setSelectionForeground(new Color(255, 255, 255)); + messageList.setSelectionBackground(new Color(102, 0, 153)); + messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + messageList.setForeground(new Color(255, 255, 255)); + messageList.setBackground(new Color(51, 51, 51)); + + DefaultListModel messageListModel = new DefaultListModel<>(); + messageList.setModel(messageListModel); + messageList.setFont(new Font("Arial", Font.PLAIN, 17)); + messageList.setFixedCellHeight(60); + messageList.setBorder(new EmptyBorder(5, 5, 5, 5)); + + JScrollPane scrollPane = new JScrollPane(); + scrollPane.setForeground(new Color(0, 0, 0)); + scrollPane.setBackground(new Color(51, 51, 51)); + scrollPane.setViewportView(messageList); + scrollPane.setBorder(null); + + GridBagConstraints gbc_scrollPane = new GridBagConstraints(); + gbc_scrollPane.fill = GridBagConstraints.BOTH; + gbc_scrollPane.gridwidth = 2; + gbc_scrollPane.gridx = 1; + gbc_scrollPane.gridy = 1; + + gbc_scrollPane.insets = new Insets(0, 10, 10, 10); + + contentPane.add(scrollPane, gbc_scrollPane); + + // Message enter field + messageEnterTextArea = new JTextArea(); + messageEnterTextArea.addKeyListener(new KeyAdapter() { + + @Override + public void keyReleased(KeyEvent e) { + + if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) + || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + + postMessage(messageList); + } + + } + }); + // Checks for changed Message + messageEnterTextArea.setWrapStyleWord(true); + messageEnterTextArea.setCaretColor(new Color(255, 255, 255)); + messageEnterTextArea.setForeground(new Color(255, 255, 255)); + messageEnterTextArea.setBackground(new Color(51, 51, 51)); + messageEnterTextArea.setLineWrap(true); + messageEnterTextArea.setBorder(null); + messageEnterTextArea.setFont(new Font("Arial", Font.PLAIN, 17)); + messageEnterTextArea.setBorder(new EmptyBorder(5, 5, 5, 5)); + + GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); + gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; + gbc_messageEnterTextfield.gridx = 1; + gbc_messageEnterTextfield.gridy = 2; + + gbc_messageEnterTextfield.insets = new Insets(10, 10, 10, 10); + + contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); + + // Post Button + JButton postButton = new JButton("Post"); + postButton.setForeground(new Color(255, 255, 255)); + postButton.setBackground(new Color(102, 51, 153)); + postButton.setBorderPainted(false); + + GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); + + gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; + gbc_moveSelectionPostButton.gridx = 2; + gbc_moveSelectionPostButton.gridy = 2; + + gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); + + postButton.addActionListener((evt) -> { postMessage(messageList); }); + contentPane.add(postButton, gbc_moveSelectionPostButton); + + // Settings Button + JButton settingsButton = new JButton("Settings"); + settingsButton.setForeground(new Color(255, 255, 255)); + settingsButton.setBackground(new Color(102, 51, 153)); + settingsButton.setBorderPainted(false); + + GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); + + gbc_moveSelectionSettingsButton.fill = GridBagConstraints.BOTH; + gbc_moveSelectionSettingsButton.gridx = 2; + gbc_moveSelectionSettingsButton.gridy = 0; + + gbc_moveSelectionSettingsButton.insets = new Insets(10, 10, 10, 10); + + settingsButton.addActionListener((evt) -> { + try { + SettingsScreen.open(localDB.getUser().getName()); + } catch (Exception e) { + SettingsScreen.open(); + System.err.println("An error occured while opening the settings screen: " + e); + e.printStackTrace(); + } + }); + contentPane.add(settingsButton, gbc_moveSelectionSettingsButton); + + // Partner name display + JTextPane textPane = new JTextPane(); + textPane.setBackground(new Color(0, 0, 0)); + textPane.setForeground(new Color(255, 255, 255)); + + textPane.setFont(new Font("Arial", Font.PLAIN, 20)); + + GridBagConstraints gbc_partnerName = new GridBagConstraints(); + gbc_partnerName.fill = GridBagConstraints.HORIZONTAL; + gbc_partnerName.gridx = 1; + gbc_partnerName.gridy = 0; + + gbc_partnerName.insets = new Insets(0, 10, 0, 10); + contentPane.add(textPane, gbc_partnerName); + + userList.setCellRenderer(new UserListRenderer()); + userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + userList.addListSelectionListener((listSelectionEvent) -> { + if (!listSelectionEvent.getValueIsAdjusting()) { + @SuppressWarnings("unchecked") + final JList selectedUserList = (JList) listSelectionEvent.getSource(); + final User user = selectedUserList.getSelectedValue(); + client.setRecipient(user); + + currentChat = localDB.getChats() + .stream() + .filter(chat -> chat.getRecipient().getID() == user.getID()) + .findFirst() + .get(); + + // Set all unread messages in the chat to read + readCurrentChat(); + + client.setRecipient(user); + + textPane.setText(currentChat.getRecipient().getName()); + + messageList.setModel(currentChat.getModel()); + contentPane.revalidate(); + } + }); + + userList.setSelectionForeground(new Color(255, 255, 255)); + userList.setSelectionBackground(new Color(102, 0, 153)); + userList.setForeground(new Color(255, 255, 255)); + userList.setBackground(new Color(51, 51, 51)); + userList.setFont(new Font("Arial", Font.PLAIN, 17)); + userList.setBorder(new EmptyBorder(5, 5, 5, 5)); + + GridBagConstraints gbc_userList = new GridBagConstraints(); + gbc_userList.fill = GridBagConstraints.VERTICAL; + gbc_userList.gridx = 0; + gbc_userList.gridy = 1; + gbc_userList.anchor = GridBagConstraints.PAGE_START; + gbc_userList.insets = new Insets(0, 0, 10, 0); + + contentPane.add(userList, gbc_userList); + contentPane.revalidate(); + + loadUsersAndChats(); + startSyncThread(Config.getInstance().getSyncTimeout()); + + contentPane.revalidate(); + } + + private void postMessage(JList messageList) { + if (!client.hasRecipient()) { + JOptionPane.showMessageDialog(this, + "Please select a recipient!", + "Cannot send message", + JOptionPane.INFORMATION_MESSAGE); + } + + if (!messageEnterTextArea.getText().isEmpty()) try { + + // Create and send message object + final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient()); + currentChat.appendMessage(message); + messageList.setModel(currentChat.getModel()); + + // Clear text field + messageEnterTextArea.setText(""); + contentPane.revalidate(); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "An exception occured while sending a message. See the log for more details.", + "Exception occured", + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + + /** + * Initializes the elements of the user list by downloading them from the + * server. + * + * @since Envoy v0.1-alpha + */ + private void loadUsersAndChats() { + new Thread(() -> { + Sync users = client.getUsersListXml(); + DefaultListModel userListModel = new DefaultListModel<>(); + users.getUsers().forEach(user -> { + userListModel.addElement(user); + + // Check if user exists in local DB + if (localDB.getChats().stream().filter(c -> c.getRecipient().getID() == user.getID()).count() == 0) + localDB.getChats().add(new Chat(user)); + }); + SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); + }).start(); + } + + /** + * Updates the data model and the UI repeatedly after a certain amount of + * time. + * + * @param timeout the amount of time that passes between two requests sent to + * the server + * @since Envoy v0.1-alpha + */ + private void startSyncThread(int timeout) { + new Timer(timeout, (evt) -> { + new Thread(() -> { + + // Synchronize + localDB.applySync( + client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + + // Process unread messages + localDB.addUnreadMessagesToLocalDB(); + localDB.clearUnreadMessagesSync(); + + // Mark unread messages as read when they are in the current chat + readCurrentChat(); + + // Update UI + SwingUtilities + .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); + }).start(); + }).start(); + } + + private void updateUserStates() { + for (int i = 0; i < userList.getModel().getSize(); i++) + for (int j = 0; j < localDB.getChats().size(); j++) + if (userList.getModel().getElementAt(i).getID() == localDB.getChats().get(j).getRecipient().getID()) + userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); + } + + /** + * Marks messages in the current chat as {@code READ}. + */ + private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } +} diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java new file mode 100644 index 0000000..9053c6c --- /dev/null +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -0,0 +1,54 @@ +package envoy.client.ui; + +import java.awt.Component; +import java.text.SimpleDateFormat; + +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +import envoy.schema.Message; + +/** + * Defines how a message is displayed.
+ *
+ * + * Project: envoy-client
+ * File: UserListRenderer.java
+ * Created: 19 Oct 2019
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.1-alpha + */ +public class MessageListRenderer extends JLabel implements ListCellRenderer { + + private static final long serialVersionUID = 5164417379767181198L; + + @Override + public Component getListCellRendererComponent(JList list, Message value, int index, + boolean isSelected, boolean cellHasFocus) { + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + setOpaque(true); + + final String text = value.getContent().get(0).getText(); + final String state = value.getMetadata().getState().toString(); + final String date = value.getMetadata().getDate() == null ? "" + : new SimpleDateFormat("dd.MM.yyyy HH:mm ") + .format(value.getMetadata().getDate().toGregorianCalendar().getTime()); + + setText(String.format( + "

%s

%s :%s", + date, + text, + state)); + return this; + } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java new file mode 100644 index 0000000..7d5de28 --- /dev/null +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -0,0 +1,156 @@ +package envoy.client.ui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FlowLayout; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; + +/** + * Project: envoy-client
+ * File: SettingsScreen.java
+ * Created: 31 Oct 2019
+ * + * @author Leon Hofmeister + */ +public class SettingsScreen extends JDialog { + + private static final long serialVersionUID = -4476913491263077107L; + private final JPanel contentPanel = new JPanel(); + public static boolean enterToSend = true; + + // TODO: Add a JPanel with all the Information necessary: + // change (Picture,Username, Email, Password) and toggle(light/dark mode, + // "ctrl+enter"/"enter" + // to send a message directly) + /** + * Open the Settings screen. + * Only suited for Dev/Error mode. + * Avoid usage. + * + * @since Envoy v0.1-alpha + */ + public static void open() { open(new SettingsScreen()); } + + /** + * Opens the Settings screen.
+ * Use preferably since everyone is already initialised.
+ * It personalises the screen more. + * + * @param username The name of the User + * @param Email The Email that is associated with that Account + * @since Envoy v0.1-alpha + */ + public static void open(String username) {// , String Email) {AUSKLAMMERN, WENN ANMELDUNG PER + // EMAIL IMPLEMENTIERT IST! + open(new SettingsScreen(username)); + } + + public static void open(SettingsScreen dialog) { + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setModal(true); + dialog.setVisible(true); + } + + /** + * Builds the Settings screen.
+ * Use only as Dev/Error Mode.
+ * Avoid usage. + * + * @since Envoy v0.1-alpha + */ + public SettingsScreen() { + setBackground(Color.BLACK); + setBounds(100, 100, 450, 300); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBackground(Color.BLACK); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + contentPanel.setLayout(new BorderLayout(0, 0)); + { + JPanel buttonPane = new JPanel(); + buttonPane.setBackground(Color.BLACK); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + buttonPane.setLayout(new BorderLayout(0, 0)); + { + JButton okButton = new JButton("Save"); + okButton.setActionCommand("OK"); + buttonPane.add(okButton, BorderLayout.EAST); + getRootPane().setDefaultButton(okButton); + okButton.addActionListener((evt) -> { + // Hier später die Daten abspeichern, wenn Datenmodell implementiert ist + dispose(); + }); + } + { + JButton cancelButton = new JButton("Cancel"); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton, BorderLayout.WEST); + + cancelButton.addActionListener((evt) -> { dispose(); }); + } + } + } + + /** + * Builds the Settings screen.
+ * Use preferreably since everyone is already initialised.
+ * It personalises the screen more. + * + * @param Username The name of the User + * @param Email The Email that is associated with that Account + * @since Envoy v0.1-alpha + */ + public SettingsScreen(String Username) {// , String Email, String hashedPwd) {AUSKLAMMERN, WENN ANMELDUNG PER EMAIL + // IMPLEMENTIERT IST! + setBackground(Color.BLACK); + setBounds(100, 100, 450, 300); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBackground(Color.BLACK); + contentPanel.setLayout(new FlowLayout()); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + { + JPanel buttonPane = new JPanel(); + buttonPane.setBackground(Color.BLACK); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + buttonPane.setLayout(new BorderLayout(0, 0)); + { + JButton okButton = new JButton("Save"); + okButton.setActionCommand("OK"); + buttonPane.add(okButton, BorderLayout.EAST); + getRootPane().setDefaultButton(okButton); + okButton.addActionListener((evt) -> { + // Hier später die Daten abspeichern, wenn Datenmodell implementiert ist + dispose(); + }); + } + { + JButton cancelButton = new JButton("Cancel"); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton, BorderLayout.WEST); + + cancelButton.addActionListener((evt) -> { dispose(); }); + } + } + } + + /** + * @return true if Enter should be used to send a message instead of ctrl+enter + * @since Envoy v0.1-alpha + */ + public static boolean isEnterToSend() { return enterToSend; } + + /** + * @param enterToSend
+ * toggles whether a message should be sent via + *
+ * buttonpress "enter" or "ctrl"+"enter" + * @since Envoy v0.1-alpha + */ + public static void setEnterToSend(boolean enterForSend) { enterToSend = enterForSend; } + // TODO: Should be changed to private, but later to avoid warnings +} diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java new file mode 100644 index 0000000..c3a3baa --- /dev/null +++ b/src/main/java/envoy/client/ui/Startup.java @@ -0,0 +1,73 @@ +package envoy.client.ui; + +import java.awt.EventQueue; +import java.io.IOException; +import java.util.Properties; + +import javax.swing.JOptionPane; + +import envoy.client.Client; +import envoy.client.Config; +import envoy.client.LocalDB; +import envoy.exception.EnvoyException; + +/** + * Starts the Envoy client and prompts the user to enter their name. + * + * Project: envoy-client
+ * File: Startup.java
+ * Created: 12 Oct 2019
+ * + * @author Leon Hofmeister + * @author Maximilian Käfer + * @since Envoy v0.1-alpha + */ +public class Startup { + + public static void main(String[] args) { + Config config = Config.getInstance(); + if (args.length > 0) { + config.load(args); + } else { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + try { + Properties configProperties = new Properties(); + configProperties.load(loader.getResourceAsStream("client.properties")); + config.load(configProperties); + } catch (IOException e) { + e.printStackTrace(); + } + } + + if (!config.isInitialized()) { + System.err.println("Server or port are not defined. Exiting..."); + System.exit(1); + } + + String userName = JOptionPane.showInputDialog("Please enter your username"); + if (userName == null || userName.isEmpty()) { + System.err.println("User name is not set or empty. Exiting..."); + System.exit(1); + } + Client client = new Client(config, userName); + LocalDB localDB = new LocalDB(client.getSender()); + try { + localDB.initializeDBFile(config.getLocalDB()); + } catch (EnvoyException e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(null, + "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", + "Local DB error", + JOptionPane.WARNING_MESSAGE); + } + + EventQueue.invokeLater(() -> { + try { + ChatWindow frame = new ChatWindow(client, localDB); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java new file mode 100644 index 0000000..40bb2ad --- /dev/null +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -0,0 +1,65 @@ +package envoy.client.ui; + +import java.awt.Component; + +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +import envoy.schema.User; +import envoy.schema.User.UserStatus; + +/** + * Defines how the {@code UserList} is displayed. + * + * Project: envoy-client
+ * File: UserListRenderer.java
+ * Created: 12 Oct 2019
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.1-alpha + */ +public class UserListRenderer extends JLabel implements ListCellRenderer { + + private static final long serialVersionUID = 5164417379767181198L; + + @Override + public Component getListCellRendererComponent(JList list, User value, int index, boolean isSelected, + boolean cellHasFocus) { + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + // Enable background rendering + setOpaque(true); + + + final String name = value.getName(); + final UserStatus status = value.getStatus(); + + switch (status) { + case ONLINE: + setText(String.format( + "

%s

%s", + status, + name)); + break; + + case OFFLINE: + setText(String.format( + "

%s

%s", + status, + name)); + break; + } + + + + return this; + } +} \ No newline at end of file diff --git a/src/main/resources/client.properties b/src/main/resources/client.properties new file mode 100644 index 0000000..2641927 --- /dev/null +++ b/src/main/resources/client.properties @@ -0,0 +1,3 @@ +server=http://kske.feste-ip.net +port=43315 +localDB=.\\localDB From 30d380857c7c2fab772995ce1978b9d228cf047a Mon Sep 17 00:00:00 2001 From: derharry333 Date: Wed, 27 Nov 2019 17:07:25 +0100 Subject: [PATCH 070/474] Replaced print statements with logger statements. --- src/main/java/envoy/client/Client.java | 10 ++++++--- src/main/java/envoy/client/LocalDB.java | 21 +++++++++++-------- src/main/java/envoy/client/ui/ChatWindow.java | 5 ++++- src/main/java/envoy/client/ui/Startup.java | 10 +++++++-- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 522d44f..5b9a2b8 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,5 +1,7 @@ package envoy.client; +import java.util.logging.Logger; + import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; @@ -28,16 +30,18 @@ public class Client { private Config config; private User sender, recipient; + private static final Logger logger = Logger.getLogger(Client.class.getSimpleName()); + public Client(Config config, String username) { this.config = config; sender = getUser(username); - System.out.println("ID: " + sender.getID()); + + logger.info("ID: " + sender.getID()); } private R post(String uri, T body, Class responseBodyClass) { javax.ws.rs.client.Client client = ClientBuilder.newClient(); WebTarget target = client.target(uri); - Response response = target.request().post(Entity.entity(body, "application/xml")); R responseBody = response.readEntity(responseBodyClass); response.close(); @@ -92,7 +96,7 @@ public class Client { if (returnSenderSync.getUsers().size() == 1) { returnSender = returnSenderSync.getUsers().get(0); } else { - System.out.println("ERROR exiting..."); + logger.warning("ERROR exiting..."); } return returnSender; diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 142b687..8af3094 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -9,6 +9,7 @@ import java.io.ObjectOutputStream; import java.time.Instant; import java.util.ArrayList; import java.util.List; +import java.util.logging.Logger; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; @@ -36,6 +37,8 @@ public class LocalDB { private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; + private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); + /** * Constructs an empty local database. * @@ -80,13 +83,13 @@ public class LocalDB { localDB.createNewFile(); } catch (IOException e) { e.printStackTrace(); - System.err.println("unable to save the messages"); + logger.warning("unable to save the messages"); } try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) { out.writeObject(chats); } catch (IOException ex) { ex.printStackTrace(); - System.err.println("unable to save the messages"); + logger.warning("unable to save the messages"); } } @@ -144,7 +147,7 @@ public class LocalDB { } readMessages.getMessages().clear(); - System.out.println(sync.getMessages().size()); + logger.info(String.format("Filled sync with %d messages.", sync.getMessages().size())); return sync; } @@ -207,20 +210,20 @@ public class LocalDB { if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) { // Update local Messages to state READ - System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + "was initialized to be set to READ in localDB."); for (int j = 0; j < getChats().size(); j++) { if (getChats().get(j) .getRecipient() .getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); + logger.info("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync .getMessages() .get(i) .getMetadata() .getMessageId()) { - System.out.println("Message with ID: " + logger.info("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + "was selected."); getChats().get(j) @@ -228,7 +231,7 @@ public class LocalDB { .get(k) .getMetadata() .setState(returnSync.getMessages().get(i).getMetadata().getState()); - System.out.println("Message State is now: " + logger.info("Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); } } @@ -244,7 +247,7 @@ public class LocalDB { if (getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) { getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus()); - System.out.println(getChats().get(k).getRecipient().getStatus().toString()); + logger.info(getChats().get(k).getRecipient().getStatus().toString()); } } } @@ -342,7 +345,7 @@ public class LocalDB { for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) { if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.WAITING) { // addMessageToSync(localDB.getChats().get(i).getModel().get(j)); - System.out.println("Got Waiting Message"); + logger.info("Got Waiting Message"); sync.getMessages().add(0, getChats().get(i).getModel().get(j)); } } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 2a7ae11..c6fce27 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -10,6 +10,7 @@ import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.util.logging.Logger; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -56,6 +57,8 @@ public class ChatWindow extends JFrame { private Chat currentChat; private JTextArea messageEnterTextArea; + + private static final Logger logger = Logger.getLogger(ChatWindow.class.getSimpleName()); public ChatWindow(Client client, LocalDB localDB) { this.client = client; @@ -186,7 +189,7 @@ public class ChatWindow extends JFrame { SettingsScreen.open(localDB.getUser().getName()); } catch (Exception e) { SettingsScreen.open(); - System.err.println("An error occured while opening the settings screen: " + e); + logger.warning("An error occured while opening the settings screen: " + e); e.printStackTrace(); } }); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index c3a3baa..0fdd76f 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -3,6 +3,8 @@ package envoy.client.ui; import java.awt.EventQueue; import java.io.IOException; import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.JOptionPane; @@ -24,7 +26,11 @@ import envoy.exception.EnvoyException; */ public class Startup { + private static final Logger logger = Logger.getLogger(Client.class.getSimpleName()); + public static void main(String[] args) { + logger.setLevel(Level.ALL); + Config config = Config.getInstance(); if (args.length > 0) { config.load(args); @@ -40,13 +46,13 @@ public class Startup { } if (!config.isInitialized()) { - System.err.println("Server or port are not defined. Exiting..."); + logger.warning("Server or port are not defined. Exiting..."); System.exit(1); } String userName = JOptionPane.showInputDialog("Please enter your username"); if (userName == null || userName.isEmpty()) { - System.err.println("User name is not set or empty. Exiting..."); + logger.warning("User name is not set or empty. Exiting..."); System.exit(1); } Client client = new Client(config, userName); From f3078bf7f3ca0ce19d4255f4ec8c2edd0a217721 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 29 Nov 2019 20:48:21 +0100 Subject: [PATCH 071/474] Fixed minor Javadoc errors --- src/main/java/envoy/client/LocalDB.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index a07ba8b..44f0f19 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -47,7 +47,7 @@ public class LocalDB { /** * Constructs an empty local database. * - * @param client the user that is logged in with this client + * @param sender the user that is logged in with this client * @since Envoy v0.1-alpha */ @@ -117,7 +117,9 @@ public class LocalDB { * Creates a {@link Message} object serializable to XML. * * @param textContent The content (text) of the message + * @param recipient The recipient of the message * @return prepared {@link Message} object + * @since Envoy v0.1-alpha */ public Message createMessage(String textContent, User recipient) { Message.Metadata metaData = objectFactory.createMessageMetadata(); From b3befc351456fcb32c9a8f752bfbda68c9446b6b Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 29 Nov 2019 20:54:33 +0100 Subject: [PATCH 072/474] Deleted unnecessary blank line --- src/main/java/envoy/client/LocalDB.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 44f0f19..b1668ad 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -50,7 +50,6 @@ public class LocalDB { * @param sender the user that is logged in with this client * @since Envoy v0.1-alpha */ - public LocalDB(User sender) { this.sender = sender; try { From 652ca8d28b717a1f22681905d0b611c8e1073d44 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 2 Dec 2019 21:44:18 +0100 Subject: [PATCH 073/474] Added a test call to the system tray displaying a message --- src/main/java/envoy/client/ui/ChatWindow.java | 24 ++++++++++++++---- src/main/resources/Envoy Logo.png | Bin 0 -> 8152 bytes 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/Envoy Logo.png diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 32b024b..0eeccc0 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,11 +1,17 @@ package envoy.client.ui; +import java.awt.AWTException; import java.awt.Color; import java.awt.ComponentOrientation; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; +import java.awt.Image; import java.awt.Insets; +import java.awt.SystemTray; +import java.awt.Toolkit; +import java.awt.TrayIcon; +import java.awt.TrayIcon.MessageType; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; @@ -37,7 +43,7 @@ import envoy.schema.User; * Project: envoy-client
* File: ChatWindow.java
* Created: 28 Sep 2019
- * + * * @author Kai S. K. Engelbart * @author Maximilian Käfer * @author Leon Hofmeister @@ -122,13 +128,11 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); } - } }); // Checks for changed Message @@ -287,7 +291,7 @@ public class ChatWindow extends JFrame { /** * Initializes the elements of the user list by downloading them from the * server. - * + * * @since Envoy v0.1-alpha */ private void loadUsersAndChats() { @@ -308,7 +312,7 @@ public class ChatWindow extends JFrame { /** * Updates the data model and the UI repeatedly after a certain amount of * time. - * + * * @param timeout the amount of time that passes between two requests sent to * the server * @since Envoy v0.1-alpha @@ -346,4 +350,14 @@ public class ChatWindow extends JFrame { * Marks messages in the current chat as {@code READ}. */ private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } + + private void displayNotification(String message) throws AWTException { + SystemTray tray = SystemTray.getSystemTray(); + Image image = Toolkit.getDefaultToolkit().createImage(getClass().getResource("Envoy Logo.png")); + TrayIcon trayIcon = new TrayIcon(image, "Envoy Client"); + trayIcon.setImageAutoSize(true); + trayIcon.setToolTip("You are notified if you have unread messages."); + tray.add(trayIcon); + trayIcon.displayMessage("Envoy Client", message, MessageType.INFO); + } } diff --git a/src/main/resources/Envoy Logo.png b/src/main/resources/Envoy Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..35ef7d9fd78cc3b79454de104ae59fbb65c0b050 GIT binary patch literal 8152 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 Date: Tue, 3 Dec 2019 21:48:16 +0100 Subject: [PATCH 074/474] Moved system tray logic to StatusTrayIcon class --- src/main/java/envoy/client/ui/ChatWindow.java | 37 +++-------------- .../java/envoy/client/ui/StatusTrayIcon.java | 39 ++++++++++++++++++ .../{Envoy Logo.png => envoy_logo.png} | Bin 3 files changed, 45 insertions(+), 31 deletions(-) create mode 100644 src/main/java/envoy/client/ui/StatusTrayIcon.java rename src/main/resources/{Envoy Logo.png => envoy_logo.png} (100%) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 0eeccc0..7a5c67c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,17 +1,11 @@ package envoy.client.ui; -import java.awt.AWTException; import java.awt.Color; import java.awt.ComponentOrientation; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.awt.Image; import java.awt.Insets; -import java.awt.SystemTray; -import java.awt.Toolkit; -import java.awt.TrayIcon; -import java.awt.TrayIcon.MessageType; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; @@ -128,8 +122,8 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) - || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + if (e.getKeyCode() == KeyEvent.VK_ENTER + && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); } @@ -220,11 +214,7 @@ public class ChatWindow extends JFrame { final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = localDB.getChats() - .stream() - .filter(chat -> chat.getRecipient().getID() == user.getID()) - .findFirst() - .get(); + currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); // Set all unread messages in the chat to read readCurrentChat(); @@ -263,10 +253,7 @@ public class ChatWindow extends JFrame { private void postMessage(JList messageList) { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, - "Please select a recipient!", - "Cannot send message", - JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); } if (!messageEnterTextArea.getText().isEmpty()) try { @@ -322,8 +309,7 @@ public class ChatWindow extends JFrame { new Thread(() -> { // Synchronize - localDB.applySync( - client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); // Process unread messages localDB.addUnreadMessagesToLocalDB(); @@ -333,8 +319,7 @@ public class ChatWindow extends JFrame { readCurrentChat(); // Update UI - SwingUtilities - .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); + SwingUtilities.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); }).start(); }).start(); } @@ -350,14 +335,4 @@ public class ChatWindow extends JFrame { * Marks messages in the current chat as {@code READ}. */ private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } - - private void displayNotification(String message) throws AWTException { - SystemTray tray = SystemTray.getSystemTray(); - Image image = Toolkit.getDefaultToolkit().createImage(getClass().getResource("Envoy Logo.png")); - TrayIcon trayIcon = new TrayIcon(image, "Envoy Client"); - trayIcon.setImageAutoSize(true); - trayIcon.setToolTip("You are notified if you have unread messages."); - tray.add(trayIcon); - trayIcon.displayMessage("Envoy Client", message, MessageType.INFO); - } } diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java new file mode 100644 index 0000000..54bc3a3 --- /dev/null +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -0,0 +1,39 @@ +package envoy.client.ui; + +import java.awt.AWTException; +import java.awt.Image; +import java.awt.SystemTray; +import java.awt.Toolkit; +import java.awt.TrayIcon; + +import envoy.exception.EnvoyException; + +/** + * Project: envoy-client
+ * File: StatusTrayIcon.java
+ * Created: 3 Dec 2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha + */ +public class StatusTrayIcon { + + private TrayIcon trayIcon; + + public StatusTrayIcon() throws EnvoyException { + if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); + + Image img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("envoy_logo.png")); + TrayIcon trayIcon = new TrayIcon(img, "Envoy Client"); + trayIcon.setImageAutoSize(true); + trayIcon.setToolTip("You are notified if you have unread messages."); + try { + SystemTray.getSystemTray().add(trayIcon); + } catch (AWTException e) { + throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); + } + } + + // TODO: Add event listener + // trayIcon.displayMessage("Envoy Client", message, MessageType.INFO); +} diff --git a/src/main/resources/Envoy Logo.png b/src/main/resources/envoy_logo.png similarity index 100% rename from src/main/resources/Envoy Logo.png rename to src/main/resources/envoy_logo.png From 3d4b472afbd5b8d74fded9011a5312a811631ac0 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 4 Dec 2019 07:50:59 +0100 Subject: [PATCH 075/474] Added a small popup menu to StatusTrayIcon and loading it in Startup --- src/main/java/envoy/client/ui/Startup.java | 1 + .../java/envoy/client/ui/StatusTrayIcon.java | 21 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index c3a3baa..7b35158 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -64,6 +64,7 @@ public class Startup { EventQueue.invokeLater(() -> { try { ChatWindow frame = new ChatWindow(client, localDB); + new StatusTrayIcon().show(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 54bc3a3..7ef6877 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -2,6 +2,8 @@ package envoy.client.ui; import java.awt.AWTException; import java.awt.Image; +import java.awt.MenuItem; +import java.awt.PopupMenu; import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; @@ -24,16 +26,31 @@ public class StatusTrayIcon { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); Image img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("envoy_logo.png")); - TrayIcon trayIcon = new TrayIcon(img, "Envoy Client"); + trayIcon = new TrayIcon(img, "Envoy Client"); trayIcon.setImageAutoSize(true); trayIcon.setToolTip("You are notified if you have unread messages."); + + PopupMenu popup = new PopupMenu(); + + MenuItem exitMenuItem = new MenuItem("Exit"); + exitMenuItem.addActionListener((evt) -> System.exit(0)); + popup.add(exitMenuItem); + + trayIcon.setPopupMenu(popup); + } + + /** + * Makes this {@link StatusTrayIcon} appear in the system tray. + * @throws EnvoyException + */ + public void show() throws EnvoyException { try { SystemTray.getSystemTray().add(trayIcon); } catch (AWTException e) { throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); } } - + // TODO: Add event listener // trayIcon.displayMessage("Envoy Client", message, MessageType.INFO); } From c70416df289c748013b83545ad758b4552b5ae89 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 4 Dec 2019 18:50:06 +0100 Subject: [PATCH 076/474] Added event system + Event interface for defining event objects + EventHandler interface for defining event handlers + EventBus singleton class for managing event handlers and dispatching events --- src/main/java/envoy/client/event/Event.java | 16 ++++++++++ .../java/envoy/client/event/EventBus.java | 32 +++++++++++++++++++ .../java/envoy/client/event/EventHandler.java | 25 +++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 src/main/java/envoy/client/event/Event.java create mode 100644 src/main/java/envoy/client/event/EventBus.java create mode 100644 src/main/java/envoy/client/event/EventHandler.java diff --git a/src/main/java/envoy/client/event/Event.java b/src/main/java/envoy/client/event/Event.java new file mode 100644 index 0000000..5d2e8a3 --- /dev/null +++ b/src/main/java/envoy/client/event/Event.java @@ -0,0 +1,16 @@ +package envoy.client.event; + +/** + * Project: envoy-clientChess
+ * File: Event.javaEvent.java
+ * Created: 04.12.2019
+ * + * @author Kai S. K. Engelbart + */ +public interface Event { + + /** + * @return the data associated with this event + */ + T get(); +} diff --git a/src/main/java/envoy/client/event/EventBus.java b/src/main/java/envoy/client/event/EventBus.java new file mode 100644 index 0000000..c97844b --- /dev/null +++ b/src/main/java/envoy/client/event/EventBus.java @@ -0,0 +1,32 @@ +package envoy.client.event; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Project: envoy-clientChess
+ * File: EventBus.javaEvent.java
+ * Created: 04.12.2019
+ * + * @author Kai S. K. Engelbart + */ +public class EventBus { + + private static EventBus eventBus; + + private List handlers = new ArrayList<>(); + + private EventBus() {} + + public EventBus getInstance() { + if (eventBus == null) eventBus = new EventBus(); + return eventBus; + } + + public void register(EventHandler... handlers) { this.handlers.addAll(Arrays.asList(handlers)); } + + public void dispatch(Event event) { handlers.stream().filter(h -> h.supports().contains(event.getClass())).forEach(h -> h.handle(event)); } + + public List getHandlers() { return handlers; } +} diff --git a/src/main/java/envoy/client/event/EventHandler.java b/src/main/java/envoy/client/event/EventHandler.java new file mode 100644 index 0000000..a6e5b81 --- /dev/null +++ b/src/main/java/envoy/client/event/EventHandler.java @@ -0,0 +1,25 @@ +package envoy.client.event; + +import java.util.Set; + +/** + * Project: envoy-clientChess
+ * File: EventHandler.javaEvent.java
+ * Created: 04.12.2019
+ * + * @author Kai S. K. Engelbart + */ +public interface EventHandler { + + /** + * Consumes an event dispatched by the event bus. + * + * @param event The event dispatched by the event bus, only of supported type + */ + void handle(Event event); + + /** + * @return A set of classes this class is supposed to handle in events + */ + Set>> supports(); +} From 761db20f5f397a93532be4007dd9bbc66b1826ab Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 4 Dec 2019 18:52:48 +0100 Subject: [PATCH 077/474] Added StatusTrayIcon#displayMessageNotification method Using this method, a message object can be displayed as a OS-specific notification, which can be useful in the future to alert the user about an incoming message while the application is not in focus. --- .../java/envoy/client/ui/StatusTrayIcon.java | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 7ef6877..869e678 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -7,8 +7,10 @@ import java.awt.PopupMenu; import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; +import java.awt.TrayIcon.MessageType; import envoy.exception.EnvoyException; +import envoy.schema.Message; /** * Project: envoy-client
@@ -25,22 +27,23 @@ public class StatusTrayIcon { public StatusTrayIcon() throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); - Image img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("envoy_logo.png")); - trayIcon = new TrayIcon(img, "Envoy Client"); + Image img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("envoy_logo.png")); + trayIcon = new TrayIcon(img, "Envoy Client"); trayIcon.setImageAutoSize(true); trayIcon.setToolTip("You are notified if you have unread messages."); - + PopupMenu popup = new PopupMenu(); - + MenuItem exitMenuItem = new MenuItem("Exit"); exitMenuItem.addActionListener((evt) -> System.exit(0)); popup.add(exitMenuItem); - + trayIcon.setPopupMenu(popup); } /** * Makes this {@link StatusTrayIcon} appear in the system tray. + * * @throws EnvoyException */ public void show() throws EnvoyException { @@ -50,7 +53,14 @@ public class StatusTrayIcon { throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); } } - - // TODO: Add event listener - // trayIcon.displayMessage("Envoy Client", message, MessageType.INFO); + + /** + * Notifies the user of a message by displaying a popup. + * + * @param message the {@link Message} object to display in the popup + */ + public void displayMessageNotification(Message message) { + // TODO: Add event listener + trayIcon.displayMessage("New message received", message.getContent().get(0).getText(), MessageType.INFO); + } } From abc41a9b639c375efc3dbda5a88bb92ba775a1ac Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 4 Dec 2019 22:01:05 +0100 Subject: [PATCH 078/474] Removed unnecessary project natures in .project --- .project | 2 -- 1 file changed, 2 deletions(-) diff --git a/.project b/.project index 08d7599..49a90bb 100644 --- a/.project +++ b/.project @@ -34,7 +34,5 @@ org.eclipse.jdt.core.javanature org.eclipse.m2e.core.maven2Nature - org.jboss.tools.jst.web.kb.kbnature - org.jboss.tools.cdi.core.cdinature From e7b5eaa9599529ef7d5e10d53a0c97ced0556914 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 4 Dec 2019 22:26:24 +0100 Subject: [PATCH 079/474] Added message events, triggering message creation event + Abstract MessageEvent class with MessageCreationEvent and MessageModificationEvent subclasses + Made StatusTrayIcon an event handler - Fixed EventBus#getInstance not being static --- src/main/java/envoy/client/LocalDB.java | 15 ++++++---- .../java/envoy/client/event/EventBus.java | 4 +-- .../client/event/MessageCreationEvent.java | 18 ++++++++++++ .../java/envoy/client/event/MessageEvent.java | 20 +++++++++++++ .../event/MessageModificationEvent.java | 18 ++++++++++++ .../java/envoy/client/ui/StatusTrayIcon.java | 29 +++++++++++++------ 6 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 src/main/java/envoy/client/event/MessageCreationEvent.java create mode 100644 src/main/java/envoy/client/event/MessageEvent.java create mode 100644 src/main/java/envoy/client/event/MessageModificationEvent.java diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 3cc96a2..bf6f01a 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -13,6 +13,8 @@ import java.util.List; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; +import envoy.client.event.EventBus; +import envoy.client.event.MessageCreationEvent; import envoy.exception.EnvoyException; import envoy.schema.Message; import envoy.schema.Message.Metadata.MessageState; @@ -112,7 +114,7 @@ public class LocalDB { /** * Creates a {@link Message} object serializable to XML. - * + * * @param textContent The content (text) of the message * @return prepared {@link Message} object */ @@ -161,6 +163,9 @@ public class LocalDB { && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { // these are the unread Messages from the server unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); + + // Create and dispatch message creation event + EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); } if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() == 0 @@ -225,7 +230,7 @@ public class LocalDB { /** * Adds the unread messages returned from the server in the latest sync to the * right chats in the LocalDB. - * + * * @param localDB * @since Envoy v0.1-alpha */ @@ -243,7 +248,7 @@ public class LocalDB { * {@code READ}. *
* Adds these messages to the {@code readMessages} {@link Sync} object. - * + * * @param currentChat * @since Envoy v0.1-alpha */ @@ -259,7 +264,7 @@ public class LocalDB { /** * Adds all messages with state {@code WAITING} from the {@link LocalDB} to the * {@link Sync} object. - * + * * @since Envoy v0.1-alpha */ private void addWaitingMessagesToSync() { @@ -273,7 +278,7 @@ public class LocalDB { /** * Clears the {@code unreadMessagesSync} {@link Sync} object. - * + * * @since Envoy v0.1-alpha */ public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } diff --git a/src/main/java/envoy/client/event/EventBus.java b/src/main/java/envoy/client/event/EventBus.java index c97844b..f1c40fc 100644 --- a/src/main/java/envoy/client/event/EventBus.java +++ b/src/main/java/envoy/client/event/EventBus.java @@ -8,7 +8,7 @@ import java.util.List; * Project: envoy-clientChess
* File: EventBus.javaEvent.java
* Created: 04.12.2019
- * + * * @author Kai S. K. Engelbart */ public class EventBus { @@ -19,7 +19,7 @@ public class EventBus { private EventBus() {} - public EventBus getInstance() { + public static EventBus getInstance() { if (eventBus == null) eventBus = new EventBus(); return eventBus; } diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java new file mode 100644 index 0000000..28f1b58 --- /dev/null +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -0,0 +1,18 @@ +package envoy.client.event; + +import envoy.schema.Message; + +/** + * Project: envoy-client
+ * File: MessageCreationEvent.java
+ * Created: 4 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class MessageCreationEvent extends MessageEvent { + + /** + * @param message the {@link Message} that has been created + */ + public MessageCreationEvent(Message message) { super(message); } +} diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java new file mode 100644 index 0000000..014a7bb --- /dev/null +++ b/src/main/java/envoy/client/event/MessageEvent.java @@ -0,0 +1,20 @@ +package envoy.client.event; + +import envoy.schema.Message; + +/** + * Project: envoy-client
+ * File: MessageCreationEvent.java
+ * Created: 4 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class MessageEvent implements Event { + + protected final Message message; + + public MessageEvent(Message message) { this.message = message; } + + @Override + public Message get() { return message; } +} diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java new file mode 100644 index 0000000..0b83ef0 --- /dev/null +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -0,0 +1,18 @@ +package envoy.client.event; + +import envoy.schema.Message; + +/** + * Project: envoy-client
+ * File: MessageModificationEvent.java
+ * Created: 4 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class MessageModificationEvent extends MessageEvent { + + /** + * @param message the {@link Message} that has been modified + */ + public MessageModificationEvent(Message message) { super(message); } +} diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 869e678..ab668e1 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -8,9 +8,14 @@ import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.TrayIcon.MessageType; +import java.util.HashSet; +import java.util.Set; +import envoy.client.event.Event; +import envoy.client.event.EventBus; +import envoy.client.event.EventHandler; +import envoy.client.event.MessageCreationEvent; import envoy.exception.EnvoyException; -import envoy.schema.Message; /** * Project: envoy-client
@@ -20,7 +25,7 @@ import envoy.schema.Message; * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha */ -public class StatusTrayIcon { +public class StatusTrayIcon implements EventHandler { private TrayIcon trayIcon; @@ -39,11 +44,12 @@ public class StatusTrayIcon { popup.add(exitMenuItem); trayIcon.setPopupMenu(popup); + EventBus.getInstance().register(this); } /** * Makes this {@link StatusTrayIcon} appear in the system tray. - * + * * @throws EnvoyException */ public void show() throws EnvoyException { @@ -55,12 +61,17 @@ public class StatusTrayIcon { } /** - * Notifies the user of a message by displaying a popup. - * - * @param message the {@link Message} object to display in the popup + * Notifies the user of a message by displaying a pop-up. */ - public void displayMessageNotification(Message message) { - // TODO: Add event listener - trayIcon.displayMessage("New message received", message.getContent().get(0).getText(), MessageType.INFO); + @Override + public void handle(Event event) { + trayIcon.displayMessage("New message received", ((MessageCreationEvent) event).get().getContent().get(0).getText(), MessageType.INFO); + } + + @Override + public Set>> supports() { + Set>> supportedEvents = new HashSet<>(); + supportedEvents.add(MessageCreationEvent.class); + return supportedEvents; } } From cf6735f621205c6260946afddf4f5aee0289f9f0 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 4 Dec 2019 23:27:17 +0100 Subject: [PATCH 080/474] Added Javadoc to event related classes and StatusTrayIcon --- src/main/java/envoy/client/LocalDB.java | 1 - src/main/java/envoy/client/event/Event.java | 1 + .../java/envoy/client/event/EventBus.java | 57 ++++++++++++++++--- .../java/envoy/client/ui/StatusTrayIcon.java | 28 ++++++++- 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index bf6f01a..c080541 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -49,7 +49,6 @@ public class LocalDB { * @param client the user that is logged in with this client * @since Envoy v0.1-alpha */ - public LocalDB(User sender) { this.sender = sender; try { diff --git a/src/main/java/envoy/client/event/Event.java b/src/main/java/envoy/client/event/Event.java index 5d2e8a3..9db2477 100644 --- a/src/main/java/envoy/client/event/Event.java +++ b/src/main/java/envoy/client/event/Event.java @@ -6,6 +6,7 @@ package envoy.client.event; * Created: 04.12.2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public interface Event { diff --git a/src/main/java/envoy/client/event/EventBus.java b/src/main/java/envoy/client/event/EventBus.java index f1c40fc..f6da3f5 100644 --- a/src/main/java/envoy/client/event/EventBus.java +++ b/src/main/java/envoy/client/event/EventBus.java @@ -5,28 +5,67 @@ import java.util.Arrays; import java.util.List; /** - * Project: envoy-clientChess
- * File: EventBus.javaEvent.java
+ * This class handles events by allowing {@link EventHandler} object to register + * themselves and then be notified about certain events dispatched by the event + * bus.
+ *
+ * The event bus is a singleton and can be used across the entire application to + * guarantee the propagation of events. + * Project: envoy-client
+ * File: EventBus.java
* Created: 04.12.2019
- * + * * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public class EventBus { - private static EventBus eventBus; - + /** + * Contains all {@link EventHandler} instances registered at this + * {@link EventBus}. + */ private List handlers = new ArrayList<>(); + /** + * The singleton instance of this {@link EventBus} that is used across the + * entire application. + */ + private static EventBus eventBus = new EventBus(); + + /** + * This constructor is not accessible from outside this class because a + * singleton instance of it is provided by the {@link EventBus#getInstance()} + * method. + */ private EventBus() {} - public static EventBus getInstance() { - if (eventBus == null) eventBus = new EventBus(); - return eventBus; - } + /** + * @return the singleton instance of the {@link EventBus} + * @since Envoy v0.2-alpha + */ + public static EventBus getInstance() { return eventBus; } + /** + * Registers a list of {@link EventHandler} objects to be notified when a + * {@link Event} is dispatched that they are subscribed to. + * + * @param handlers the {@link EventHandler} objects to register + * @since Envoy v0.2-alpha + */ public void register(EventHandler... handlers) { this.handlers.addAll(Arrays.asList(handlers)); } + /** + * Dispatches a {@link Event} to every {@link EventHandler} subscribed to it. + * + * @param event the {@link Event} to dispatch + * @since Envoy v0.2-alpha + */ public void dispatch(Event event) { handlers.stream().filter(h -> h.supports().contains(event.getClass())).forEach(h -> h.handle(event)); } + /** + * @return a list of all {@link EventHandler} instances currently registered at + * this {@link EventBus} + * @since Envoy v0.2-alpha + */ public List getHandlers() { return handlers; } } diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index ab668e1..951fbd4 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -27,8 +27,20 @@ import envoy.exception.EnvoyException; */ public class StatusTrayIcon implements EventHandler { + /** + * The {@link TrayIcon} provided by the System Tray API for controlling the + * system tray. This includes displaying the icon, but also creating + * notifications when new messages are received. + */ private TrayIcon trayIcon; + /** + * Creates a {@link StatusTrayIcon} with the Envoy logo, a tool tip and a pop-up + * menu. + * + * @throws EnvoyException if the currently used OS does not support the System + * Tray API + */ public StatusTrayIcon() throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); @@ -50,7 +62,9 @@ public class StatusTrayIcon implements EventHandler { /** * Makes this {@link StatusTrayIcon} appear in the system tray. * - * @throws EnvoyException + * @throws EnvoyException if the status icon could not be attaches to the system + * tray for system-internal reasons + * @since Envoy v0.2-alpha */ public void show() throws EnvoyException { try { @@ -61,13 +75,23 @@ public class StatusTrayIcon implements EventHandler { } /** - * Notifies the user of a message by displaying a pop-up. + * Notifies the user of a message by displaying a pop-up every time a new + * message is received. + * + * @since Envoy v0.2-alpha */ @Override public void handle(Event event) { trayIcon.displayMessage("New message received", ((MessageCreationEvent) event).get().getContent().get(0).getText(), MessageType.INFO); } + /** + * The {@link StatusTrayIcon} only reacts to {@link MessageCreationEvent} + * instances which signify newly received messages. + * + * @return A set with the single element {@code MessageCreationEvent.class} + * @since Envoy v0.2-alpha + */ @Override public Set>> supports() { Set>> supportedEvents = new HashSet<>(); From 25181a1408081fce5f5ce31e7bf15e3a8523012b Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 5 Dec 2019 15:05:05 +0100 Subject: [PATCH 081/474] Simplified and optimized sync related code in LocalDB --- src/main/java/envoy/client/LocalDB.java | 141 ++++++++++++------------ 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index c080541..d15e62a 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -147,80 +147,83 @@ public class LocalDB { public void applySync(Sync returnSync) { for (int i = 0; i < returnSync.getMessages().size(); i++) { - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.SENT) { - // Update Local Messages with State WAITING (add Message ID and change State to - // SENT) - for (int j = 0; j < sync.getMessages().size(); j++) { - if (j == i) { - sync.getMessages().get(j).getMetadata().setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId()); - sync.getMessages().get(j).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState()); - } - } - } - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() != 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { - // these are the unread Messages from the server - unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); - // Create and dispatch message creation event - EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); - } + // The message has an ID + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0) { - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() == 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { - // Update Messages in localDB to state RECEIVED - for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() - .get(i) - .getMetadata() - .getMessageId()) { - // Update Message in LocalDB - getChats().get(j).getModel().get(k).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState()); + // Messages are processes differently corresponding to their state + switch (returnSync.getMessages().get(i).getMetadata().getState()) { + case SENT: + // Update previously waiting and now sent messages that were assigned an ID by + // the server + sync.getMessages().get(i).getMetadata().setMessageId(returnSync.getMessages().get(i).getMetadata().getMessageId()); + sync.getMessages().get(i).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + break; + case RECEIVED: + if (returnSync.getMessages().get(i).getMetadata().getSender() != 0) { + // these are the unread Messages from the server + unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); + + // Create and dispatch message creation event + EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); + } else { + // Update Messages in localDB to state RECEIVED + for (int j = 0; j < getChats().size(); j++) { + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() + .get(i) + .getMetadata() + .getMessageId()) { + // Update Message in LocalDB + getChats().get(j) + .getModel() + .get(k) + .getMetadata() + .setState(returnSync.getMessages().get(j).getMetadata().getState()); + } + } + } } } - } - } - - } - - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) { - // Update local Messages to state READ - System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() - + "was initialized to be set to READ in localDB."); - for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); - for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() - .get(i) - .getMetadata() - .getMessageId()) { - System.out.println( - "Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + "was selected."); - getChats().get(j).getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - System.out - .println("Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); + break; + case READ: + // Update local Messages to state READ + System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + + "was initialized to be set to READ in localDB."); + for (int j = 0; j < getChats().size(); j++) { + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); + for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() + .get(i) + .getMetadata() + .getMessageId()) { + System.out.println("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + + "was selected."); + getChats().get(j) + .getModel() + .get(k) + .getMetadata() + .setState(returnSync.getMessages().get(i).getMetadata().getState()); + System.out.println( + "Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); + } + } } } - } + break; } } } // Updating UserStatus of all users in LocalDB - for (int j = 0; j < returnSync.getUsers().size(); j++) { - for (int k = 0; k < getChats().size(); k++) { - if (getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) { - - getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus()); - System.out.println(getChats().get(k).getRecipient().getStatus().toString()); + for (User user : returnSync.getUsers()) + for (Chat chat : getChats()) + if (user.getID() == chat.getRecipient().getID()) { + chat.getRecipient().setStatus(user.getStatus()); + System.out.println(chat.getRecipient().getStatus()); } - } - } sync.getMessages().clear(); sync.getUsers().clear(); @@ -234,11 +237,11 @@ public class LocalDB { * @since Envoy v0.1-alpha */ public void addUnreadMessagesToLocalDB() { - Sync unreadMessages = unreadMessagesSync; - for (int i = 0; i < unreadMessages.getMessages().size(); i++) - for (int j = 0; j < getChats().size(); j++) - if (getChats().get(j).getRecipient().getID() == unreadMessages.getMessages().get(i).getMetadata().getSender()) { - getChats().get(j).appendMessage(unreadMessages.getMessages().get(i)); + for(Message message : unreadMessagesSync.getMessages()) + for(Chat chat : getChats()) + if(message.getMetadata().getSender() == chat.getRecipient().getID()) { + chat.appendMessage(message); + break; } } @@ -283,8 +286,8 @@ public class LocalDB { public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } /** - * @return all saves {@link Chat} objects that list the client user as the - * client + * @return all saved {@link Chat} objects that list the client user as the + * sender * @since Envoy v0.1-alpha **/ public List getChats() { return chats; } From ca4369d60e5bc6436e415aa7a8245201e221b0dc Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 5 Dec 2019 15:13:19 +0100 Subject: [PATCH 082/474] Fixed Envoy logo loading for StatusTrayIcon --- src/main/java/envoy/client/ui/StatusTrayIcon.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 951fbd4..94d30d0 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -44,7 +44,8 @@ public class StatusTrayIcon implements EventHandler { public StatusTrayIcon() throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); - Image img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("envoy_logo.png")); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + Image img = Toolkit.getDefaultToolkit().createImage(loader.getResource("envoy_logo.png")); trayIcon = new TrayIcon(img, "Envoy Client"); trayIcon.setImageAutoSize(true); trayIcon.setToolTip("You are notified if you have unread messages."); From d105c48c9e38ed913b4f41ba6e4f28e225189362 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 5 Dec 2019 15:42:20 +0100 Subject: [PATCH 083/474] Creating message notifications only if ChatWindow has lost focus StatusTray injects a WindowFocusListener into ChatWindow in its constructor and does only react to received messages if ChatWindow has currently lost focus. --- src/main/java/envoy/client/ui/Startup.java | 6 ++-- .../java/envoy/client/ui/StatusTrayIcon.java | 35 ++++++++++++++++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 7b35158..6333a60 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -63,9 +63,9 @@ public class Startup { EventQueue.invokeLater(() -> { try { - ChatWindow frame = new ChatWindow(client, localDB); - new StatusTrayIcon().show(); - frame.setVisible(true); + ChatWindow chatWindow = new ChatWindow(client, localDB); + new StatusTrayIcon(chatWindow).show(); + chatWindow.setVisible(true); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 94d30d0..827296d 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -8,6 +8,8 @@ import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.TrayIcon.MessageType; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.util.HashSet; import java.util.Set; @@ -16,6 +18,7 @@ import envoy.client.event.EventBus; import envoy.client.event.EventHandler; import envoy.client.event.MessageCreationEvent; import envoy.exception.EnvoyException; +import envoy.schema.Message; /** * Project: envoy-client
@@ -34,6 +37,12 @@ public class StatusTrayIcon implements EventHandler { */ private TrayIcon trayIcon; + /** + * A received {@link Message} is only displayed as a system tray notification if + * this variable is set to {@code true}. + */ + private boolean displayMessages = false; + /** * Creates a {@link StatusTrayIcon} with the Envoy logo, a tool tip and a pop-up * menu. @@ -41,11 +50,11 @@ public class StatusTrayIcon implements EventHandler { * @throws EnvoyException if the currently used OS does not support the System * Tray API */ - public StatusTrayIcon() throws EnvoyException { + public StatusTrayIcon(ChatWindow chatWindow) throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - Image img = Toolkit.getDefaultToolkit().createImage(loader.getResource("envoy_logo.png")); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + Image img = Toolkit.getDefaultToolkit().createImage(loader.getResource("envoy_logo.png")); trayIcon = new TrayIcon(img, "Envoy Client"); trayIcon.setImageAutoSize(true); trayIcon.setToolTip("You are notified if you have unread messages."); @@ -57,6 +66,22 @@ public class StatusTrayIcon implements EventHandler { popup.add(exitMenuItem); trayIcon.setPopupMenu(popup); + + // Only display messages if the chat window is not focused + chatWindow.addWindowFocusListener(new WindowAdapter() { + + @Override + public void windowGainedFocus(WindowEvent e) { + displayMessages = false; + } + + @Override + public void windowLostFocus(WindowEvent e) { + displayMessages = true; + } + }); + + // Start processing message events EventBus.getInstance().register(this); } @@ -83,7 +108,9 @@ public class StatusTrayIcon implements EventHandler { */ @Override public void handle(Event event) { - trayIcon.displayMessage("New message received", ((MessageCreationEvent) event).get().getContent().get(0).getText(), MessageType.INFO); + System.out.println("Message received. Displaying message: " + displayMessages); + if (displayMessages) + trayIcon.displayMessage("New message received", ((MessageCreationEvent) event).get().getContent().get(0).getText(), MessageType.INFO); } /** From c5988731e16d79e73a754949e9dc5396ab31fac4 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 5 Dec 2019 16:10:28 +0100 Subject: [PATCH 084/474] Re-added logging to LocalDB to resolve merge conflict --- src/main/java/envoy/client/LocalDB.java | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index d15e62a..d3ed430 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -9,6 +9,7 @@ import java.io.ObjectOutputStream; import java.time.Instant; import java.util.ArrayList; import java.util.List; +import java.util.logging.Logger; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; @@ -43,6 +44,8 @@ public class LocalDB { private Sync sync = objectFactory.createSync(); private Sync readMessages = objectFactory.createSync(); + private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); + /** * Constructs an empty local database. * @@ -85,13 +88,13 @@ public class LocalDB { localDB.createNewFile(); } catch (IOException e) { e.printStackTrace(); - System.err.println("unable to save the messages"); + logger.warning("unable to save the messages"); } try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) { out.writeObject(chats); } catch (IOException ex) { ex.printStackTrace(); - System.err.println("unable to save the messages"); + logger.warning("unable to save the messages"); } } @@ -141,7 +144,7 @@ public class LocalDB { sync.getMessages().addAll(readMessages.getMessages()); readMessages.getMessages().clear(); - System.out.println(sync.getMessages().size()); + logger.info(String.format("Filled sync with %d messages.", sync.getMessages().size())); return sync; } @@ -189,24 +192,24 @@ public class LocalDB { break; case READ: // Update local Messages to state READ - System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + "was initialized to be set to READ in localDB."); for (int j = 0; j < getChats().size(); j++) { if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); + logger.info("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() .get(i) .getMetadata() .getMessageId()) { - System.out.println("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + logger.info("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + "was selected."); getChats().get(j) .getModel() .get(k) .getMetadata() .setState(returnSync.getMessages().get(i).getMetadata().getState()); - System.out.println( + logger.info( "Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); } } @@ -222,7 +225,7 @@ public class LocalDB { for (Chat chat : getChats()) if (user.getID() == chat.getRecipient().getID()) { chat.getRecipient().setStatus(user.getStatus()); - System.out.println(chat.getRecipient().getStatus()); + logger.info(chat.getRecipient().getStatus().toString()); } sync.getMessages().clear(); @@ -273,7 +276,7 @@ public class LocalDB { for (Chat chat : getChats()) for (int i = 0; i < chat.getModel().size(); i++) if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) { - System.out.println("Got Waiting Message"); + logger.info("Got Waiting Message"); sync.getMessages().add(chat.getModel().get(i)); } } From eaa1e4e1aef3b81cbf2987d2c809d0a4e704d2db Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 5 Dec 2019 16:17:33 +0100 Subject: [PATCH 085/474] Javadoc fixes and using superclass when injecting WindowFocusListener --- src/main/java/envoy/client/LocalDB.java | 4 +++- src/main/java/envoy/client/ui/StatusTrayIcon.java | 14 +++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index d3ed430..8caea75 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -49,7 +49,7 @@ public class LocalDB { /** * Constructs an empty local database. * - * @param client the user that is logged in with this client + * @param sender the user that is logged in with this client * @since Envoy v0.1-alpha */ public LocalDB(User sender) { @@ -118,7 +118,9 @@ public class LocalDB { * Creates a {@link Message} object serializable to XML. * * @param textContent The content (text) of the message + * @param recipient The recipient of the message * @return prepared {@link Message} object + * @since Envoy v0.1-alpha */ public Message createMessage(String textContent, User recipient) { Message.Metadata metaData = objectFactory.createMessageMetadata(); diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 827296d..01cc8d7 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -8,6 +8,7 @@ import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.TrayIcon.MessageType; +import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.HashSet; @@ -46,11 +47,14 @@ public class StatusTrayIcon implements EventHandler { /** * Creates a {@link StatusTrayIcon} with the Envoy logo, a tool tip and a pop-up * menu. - * + * + * @param focusTarget the {@link Window} which focus determines if message + * notifications are displayed * @throws EnvoyException if the currently used OS does not support the System * Tray API + * @since Envoy v0.2-alpha */ - public StatusTrayIcon(ChatWindow chatWindow) throws EnvoyException { + public StatusTrayIcon(Window focusTarget) throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); ClassLoader loader = Thread.currentThread().getContextClassLoader(); @@ -68,7 +72,7 @@ public class StatusTrayIcon implements EventHandler { trayIcon.setPopupMenu(popup); // Only display messages if the chat window is not focused - chatWindow.addWindowFocusListener(new WindowAdapter() { + focusTarget.addWindowFocusListener(new WindowAdapter() { @Override public void windowGainedFocus(WindowEvent e) { @@ -103,7 +107,7 @@ public class StatusTrayIcon implements EventHandler { /** * Notifies the user of a message by displaying a pop-up every time a new * message is received. - * + * * @since Envoy v0.2-alpha */ @Override @@ -116,7 +120,7 @@ public class StatusTrayIcon implements EventHandler { /** * The {@link StatusTrayIcon} only reacts to {@link MessageCreationEvent} * instances which signify newly received messages. - * + * * @return A set with the single element {@code MessageCreationEvent.class} * @since Envoy v0.2-alpha */ From f7bb3e67894378d2ca1c796e9d91384ea0122b5a Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 7 Dec 2019 09:53:55 +0100 Subject: [PATCH 086/474] Implemented changes requested by @delvh --- .settings/org.eclipse.jdt.core.prefs | 99 +++++++++++++++++++ src/main/java/envoy/client/LocalDB.java | 67 ++++++------- src/main/java/envoy/client/ui/ChatWindow.java | 1 + 3 files changed, 131 insertions(+), 36 deletions(-) diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index cb635b1..262bd4f 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,107 @@ eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnull.secondary= +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary= +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullable.secondary= +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.APILeak=warning +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled +org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=1.8 diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 1989f89..3929315 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -140,6 +140,13 @@ public class LocalDB { return message; } + /** + * Creates a {@link Sync} object filled with the changes that occurred to the + * local database since the last synchronization. + * + * @param userId the ID of the user that is synchronized by this client + * @return {@link Sync} object filled with the current changes + */ public Sync fillSync(long userId) { addWaitingMessagesToSync(); @@ -150,6 +157,11 @@ public class LocalDB { return sync; } + /** + * Applies the changes carried by a {@link Sync} object to the local database + * + * @param returnSync the {@link Sync} object to apply + */ public void applySync(Sync returnSync) { for (int i = 0; i < returnSync.getMessages().size(); i++) { @@ -173,50 +185,33 @@ public class LocalDB { EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); } else { // Update Messages in localDB to state RECEIVED - for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() - .get(i) - .getMetadata() - .getMessageId()) { - // Update Message in LocalDB - getChats().get(j) - .getModel() - .get(k) - .getMetadata() - .setState(returnSync.getMessages().get(j).getMetadata().getState()); - } - } - } - } + for (Chat chat : getChats()) + if (chat.getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) + for (int j = 0; j < chat.getModel().getSize(); j++) + if (chat.getModel().get(j).getMetadata().getMessageId() == returnSync.getMessages() + .get(i) + .getMetadata() + .getMessageId()) + chat.getModel().get(j).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); } break; case READ: // Update local Messages to state READ logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + "was initialized to be set to READ in localDB."); - for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - logger.info("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); - for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() + for (Chat chat : getChats()) + if (chat.getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + logger.info("Chat with: " + chat.getRecipient().getID() + "was selected."); + for (int k = 0; k < chat.getModel().getSize(); k++) + if (chat.getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() .get(i) .getMetadata() .getMessageId()) { - logger.info("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() - + "was selected."); - getChats().get(j) - .getModel() - .get(k) - .getMetadata() - .setState(returnSync.getMessages().get(i).getMetadata().getState()); - logger.info( - "Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); + logger.info("Message with ID: " + chat.getModel().get(k).getMetadata().getMessageId() + "was selected."); + chat.getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + logger.info("Message State is now: " + chat.getModel().get(k).getMetadata().getState()); } - } } - } break; } } @@ -242,9 +237,9 @@ public class LocalDB { * @since Envoy v0.1-alpha */ public void addUnreadMessagesToLocalDB() { - for(Message message : unreadMessagesSync.getMessages()) - for(Chat chat : getChats()) - if(message.getMetadata().getSender() == chat.getRecipient().getID()) { + for (Message message : unreadMessagesSync.getMessages()) + for (Chat chat : getChats()) + if (message.getMetadata().getSender() == chat.getRecipient().getID()) { chat.appendMessage(message); break; } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index cefe886..e6e6872 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -257,6 +257,7 @@ public class ChatWindow extends JFrame { private void postMessage(JList messageList) { if (!client.hasRecipient()) { JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); + return; } if (!messageEnterTextArea.getText().isEmpty()) try { From 354f46d0cf9c14fb1a169ce8617dbdd01fcbb700 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 7 Dec 2019 10:44:25 +0100 Subject: [PATCH 087/474] Improved logging and code readability --- src/main/java/envoy/client/Client.java | 20 +- src/main/java/envoy/client/Config.java | 2 +- src/main/java/envoy/client/LocalDB.java | 45 +- src/main/java/envoy/client/ui/ChatWindow.java | 704 +++++++++--------- .../envoy/client/ui/MessageListRenderer.java | 101 ++- .../java/envoy/client/ui/SettingsScreen.java | 10 +- src/main/java/envoy/client/ui/Startup.java | 23 +- .../envoy/client/ui/UserListRenderer.java | 119 ++- 8 files changed, 497 insertions(+), 527 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 5b9a2b8..4c775e1 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -36,14 +36,14 @@ public class Client { this.config = config; sender = getUser(username); - logger.info("ID: " + sender.getID()); + logger.info("ID: " + sender.getID()); } private R post(String uri, T body, Class responseBodyClass) { - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client.target(uri); - Response response = target.request().post(Entity.entity(body, "application/xml")); - R responseBody = response.readEntity(responseBodyClass); + javax.ws.rs.client.Client client = ClientBuilder.newClient(); + WebTarget target = client.target(uri); + Response response = target.request().post(Entity.entity(body, "application/xml")); + R responseBody = response.readEntity(responseBodyClass); response.close(); client.close(); @@ -133,7 +133,9 @@ public class Client { * Updating UserStatus of all users in LocalDB. (Server sends all users with * their updated UserStatus to the client.)
* - * @param userId + * @param userId the id of the {@link Client} who sends the {@link Sync} + * @param sync the {@link Sync} to send + * @return a sync * @since Envoy v0.1-alpha */ public Sync sendSync(long userId, Sync sync) { @@ -168,16 +170,16 @@ public class Client { public User getRecipient() { return recipient; } /** - * Sets the recipient. + * Sets the recipient. + * * @param recipient - the recipient to set * @since Envoy v0.1-alpha */ public void setRecipient(User recipient) { this.recipient = recipient; } - /** + /** * @return true, if a recipient is selected * @since Envoy v0.1-alpha */ public boolean hasRecipient() { return recipient != null; } } - diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 545df2f..116a341 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -114,7 +114,7 @@ public class Config { * Changes the default local database. * Exclusively intended for development purposes. * - * @param the file containing the local database + * @param localDB the file containing the local database * @since Envoy v0.1-alpha **/ public void setLocalDB(File localDB) { this.localDB = localDB; } diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index b1668ad..ba5e3a3 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -39,7 +39,7 @@ public class LocalDB { private DatatypeFactory datatypeFactory; private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); - + private Sync unreadMessagesSync = objectFactory.createSync(); private Sync sync = objectFactory.createSync(); private Sync readMessages = objectFactory.createSync(); @@ -80,19 +80,13 @@ public class LocalDB { * @throws IOException if something went wrong during saving * @since Envoy v0.1-alpha */ - public void saveToLocalDB() { - try { - localDB.getParentFile().mkdirs(); - localDB.createNewFile(); - } catch (IOException e) { - e.printStackTrace(); - logger.warning("unable to save the messages"); - } + public void saveToLocalDB() throws IOException { + localDB.getParentFile().mkdirs(); + localDB.createNewFile(); try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) { out.writeObject(chats); } catch (IOException ex) { - ex.printStackTrace(); - logger.warning("unable to save the messages"); + throw ex; } } @@ -116,7 +110,7 @@ public class LocalDB { * Creates a {@link Message} object serializable to XML. * * @param textContent The content (text) of the message - * @param recipient The recipient of the message + * @param recipient The recipient of the message * @return prepared {@link Message} object * @since Envoy v0.1-alpha */ @@ -144,7 +138,7 @@ public class LocalDB { sync.getMessages().addAll(readMessages.getMessages()); readMessages.getMessages().clear(); - logger.info(String.format("Filled sync with %d messages.", sync.getMessages().size())); + logger.finest(String.format("Filled sync with %d messages.", sync.getMessages().size())); return sync; } @@ -189,28 +183,20 @@ public class LocalDB { if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) { // Update local Messages to state READ - logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + logger.finest("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + "was initialized to be set to READ in localDB."); for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j) - .getRecipient() - .getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - logger.info("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + logger.fine("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() .get(i) .getMetadata() .getMessageId()) { - logger.info("Message with ID: " - + getChats().get(j).getModel().get(k).getMetadata().getMessageId() - + "was selected."); - getChats().get(j) - .getModel() - .get(k) - .getMetadata() - .setState(returnSync.getMessages().get(i).getMetadata().getState()); - logger.info("Message State is now: " - + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); + logger + .finest("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + "was selected."); + getChats().get(j).getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + logger.finest("Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); } } } @@ -237,7 +223,6 @@ public class LocalDB { * Adds the unread messages returned from the server in the latest sync to the * right chats in the LocalDB. * - * @param localDB * @since Envoy v0.1-alpha */ public void addUnreadMessagesToLocalDB() { @@ -255,7 +240,7 @@ public class LocalDB { *
* Adds these messages to the {@code readMessages} {@link Sync} object. * - * @param currentChat + * @param currentChat the {@link Chat} that was just opened * @since Envoy v0.1-alpha */ public void setMessagesToRead(Chat currentChat) { diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 39a907f..e36a3f0 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,352 +1,352 @@ -package envoy.client.ui; - -import java.awt.Color; -import java.awt.ComponentOrientation; -import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.logging.Logger; - -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JList; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.JTextPane; -import javax.swing.ListSelectionModel; -import javax.swing.SwingUtilities; -import javax.swing.Timer; -import javax.swing.border.EmptyBorder; - -import envoy.client.Chat; -import envoy.client.Client; -import envoy.client.Config; -import envoy.client.LocalDB; -import envoy.schema.Message; -import envoy.schema.Sync; -import envoy.schema.User; - -/** - * Project: envoy-client
- * File: ChatWindow.java
- * Created: 28 Sep 2019
- * - * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @author Leon Hofmeister - * @since Envoy v0.1-alpha - */ -public class ChatWindow extends JFrame { - - private static final long serialVersionUID = 6865098428255463649L; - - private JPanel contentPane = new JPanel(); - - private Client client; - private LocalDB localDB; - - private JList userList = new JList<>(); - private Chat currentChat; - - private JTextArea messageEnterTextArea; - - private static final Logger logger = Logger.getLogger(ChatWindow.class.getSimpleName()); - - public ChatWindow(Client client, LocalDB localDB) { - this.client = client; - this.localDB = localDB; - - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setBounds(100, 100, 600, 800); - setTitle("Envoy"); - setLocationRelativeTo(null); - - // Save chats when window closes - addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(WindowEvent e) { localDB.saveToLocalDB(); } - }); - - contentPane.setBackground(new Color(0, 0, 0)); - contentPane.setForeground(Color.white); - contentPane.setBorder(new EmptyBorder(0, 5, 0, 0)); - setContentPane(contentPane); - GridBagLayout gbl_contentPane = new GridBagLayout(); - gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; - gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; - gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; - gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 }; - contentPane.setLayout(gbl_contentPane); - - JList messageList = new JList<>(); - messageList.setCellRenderer(new MessageListRenderer()); - - messageList.setFocusTraversalKeysEnabled(false); - messageList.setSelectionForeground(new Color(255, 255, 255)); - messageList.setSelectionBackground(new Color(102, 0, 153)); - messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); - messageList.setForeground(new Color(255, 255, 255)); - messageList.setBackground(new Color(51, 51, 51)); - - DefaultListModel messageListModel = new DefaultListModel<>(); - messageList.setModel(messageListModel); - messageList.setFont(new Font("Arial", Font.PLAIN, 17)); - messageList.setFixedCellHeight(60); - messageList.setBorder(new EmptyBorder(5, 5, 5, 5)); - - JScrollPane scrollPane = new JScrollPane(); - scrollPane.setForeground(new Color(0, 0, 0)); - scrollPane.setBackground(new Color(51, 51, 51)); - scrollPane.setViewportView(messageList); - scrollPane.setBorder(null); - - GridBagConstraints gbc_scrollPane = new GridBagConstraints(); - gbc_scrollPane.fill = GridBagConstraints.BOTH; - gbc_scrollPane.gridwidth = 2; - gbc_scrollPane.gridx = 1; - gbc_scrollPane.gridy = 1; - - gbc_scrollPane.insets = new Insets(0, 10, 10, 10); - - contentPane.add(scrollPane, gbc_scrollPane); - - // Message enter field - messageEnterTextArea = new JTextArea(); - messageEnterTextArea.addKeyListener(new KeyAdapter() { - - @Override - public void keyReleased(KeyEvent e) { - - if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) - || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { - - postMessage(messageList); - } - - } - }); - // Checks for changed Message - messageEnterTextArea.setWrapStyleWord(true); - messageEnterTextArea.setCaretColor(new Color(255, 255, 255)); - messageEnterTextArea.setForeground(new Color(255, 255, 255)); - messageEnterTextArea.setBackground(new Color(51, 51, 51)); - messageEnterTextArea.setLineWrap(true); - messageEnterTextArea.setBorder(null); - messageEnterTextArea.setFont(new Font("Arial", Font.PLAIN, 17)); - messageEnterTextArea.setBorder(new EmptyBorder(5, 5, 5, 5)); - - GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); - gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; - gbc_messageEnterTextfield.gridx = 1; - gbc_messageEnterTextfield.gridy = 2; - - gbc_messageEnterTextfield.insets = new Insets(10, 10, 10, 10); - - contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); - - // Post Button - JButton postButton = new JButton("Post"); - postButton.setForeground(new Color(255, 255, 255)); - postButton.setBackground(new Color(102, 51, 153)); - postButton.setBorderPainted(false); - - GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); - - gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; - gbc_moveSelectionPostButton.gridx = 2; - gbc_moveSelectionPostButton.gridy = 2; - - gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); - - postButton.addActionListener((evt) -> { postMessage(messageList); }); - contentPane.add(postButton, gbc_moveSelectionPostButton); - - // Settings Button - JButton settingsButton = new JButton("Settings"); - settingsButton.setForeground(new Color(255, 255, 255)); - settingsButton.setBackground(new Color(102, 51, 153)); - settingsButton.setBorderPainted(false); - - GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); - - gbc_moveSelectionSettingsButton.fill = GridBagConstraints.BOTH; - gbc_moveSelectionSettingsButton.gridx = 2; - gbc_moveSelectionSettingsButton.gridy = 0; - - gbc_moveSelectionSettingsButton.insets = new Insets(10, 10, 10, 10); - - settingsButton.addActionListener((evt) -> { - try { - SettingsScreen.open(localDB.getUser().getName()); - } catch (Exception e) { - SettingsScreen.open(); - logger.warning("An error occured while opening the settings screen: " + e); - e.printStackTrace(); - } - }); - contentPane.add(settingsButton, gbc_moveSelectionSettingsButton); - - // Partner name display - JTextPane textPane = new JTextPane(); - textPane.setBackground(new Color(0, 0, 0)); - textPane.setForeground(new Color(255, 255, 255)); - - textPane.setFont(new Font("Arial", Font.PLAIN, 20)); - - GridBagConstraints gbc_partnerName = new GridBagConstraints(); - gbc_partnerName.fill = GridBagConstraints.HORIZONTAL; - gbc_partnerName.gridx = 1; - gbc_partnerName.gridy = 0; - - gbc_partnerName.insets = new Insets(0, 10, 0, 10); - contentPane.add(textPane, gbc_partnerName); - - userList.setCellRenderer(new UserListRenderer()); - userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - userList.addListSelectionListener((listSelectionEvent) -> { - if (!listSelectionEvent.getValueIsAdjusting()) { - @SuppressWarnings("unchecked") - final JList selectedUserList = (JList) listSelectionEvent.getSource(); - final User user = selectedUserList.getSelectedValue(); - client.setRecipient(user); - - currentChat = localDB.getChats() - .stream() - .filter(chat -> chat.getRecipient().getID() == user.getID()) - .findFirst() - .get(); - - // Set all unread messages in the chat to read - readCurrentChat(); - - client.setRecipient(user); - - textPane.setText(currentChat.getRecipient().getName()); - - messageList.setModel(currentChat.getModel()); - contentPane.revalidate(); - } - }); - - userList.setSelectionForeground(new Color(255, 255, 255)); - userList.setSelectionBackground(new Color(102, 0, 153)); - userList.setForeground(new Color(255, 255, 255)); - userList.setBackground(new Color(51, 51, 51)); - userList.setFont(new Font("Arial", Font.PLAIN, 17)); - userList.setBorder(new EmptyBorder(5, 5, 5, 5)); - - GridBagConstraints gbc_userList = new GridBagConstraints(); - gbc_userList.fill = GridBagConstraints.VERTICAL; - gbc_userList.gridx = 0; - gbc_userList.gridy = 1; - gbc_userList.anchor = GridBagConstraints.PAGE_START; - gbc_userList.insets = new Insets(0, 0, 10, 0); - - contentPane.add(userList, gbc_userList); - contentPane.revalidate(); - - loadUsersAndChats(); - startSyncThread(Config.getInstance().getSyncTimeout()); - - contentPane.revalidate(); - } - - private void postMessage(JList messageList) { - if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, - "Please select a recipient!", - "Cannot send message", - JOptionPane.INFORMATION_MESSAGE); - } - - if (!messageEnterTextArea.getText().isEmpty()) try { - - // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient()); - currentChat.appendMessage(message); - messageList.setModel(currentChat.getModel()); - - // Clear text field - messageEnterTextArea.setText(""); - contentPane.revalidate(); - } catch (Exception e) { - JOptionPane.showMessageDialog(this, - "An exception occured while sending a message. See the log for more details.", - "Exception occured", - JOptionPane.ERROR_MESSAGE); - e.printStackTrace(); - } - } - - /** - * Initializes the elements of the user list by downloading them from the - * server. - * - * @since Envoy v0.1-alpha - */ - private void loadUsersAndChats() { - new Thread(() -> { - Sync users = client.getUsersListXml(); - DefaultListModel userListModel = new DefaultListModel<>(); - users.getUsers().forEach(user -> { - userListModel.addElement(user); - - // Check if user exists in local DB - if (localDB.getChats().stream().filter(c -> c.getRecipient().getID() == user.getID()).count() == 0) - localDB.getChats().add(new Chat(user)); - }); - SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); - }).start(); - } - - /** - * Updates the data model and the UI repeatedly after a certain amount of - * time. - * - * @param timeout the amount of time that passes between two requests sent to - * the server - * @since Envoy v0.1-alpha - */ - private void startSyncThread(int timeout) { - new Timer(timeout, (evt) -> { - new Thread(() -> { - - // Synchronize - localDB.applySync( - client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); - - // Process unread messages - localDB.addUnreadMessagesToLocalDB(); - localDB.clearUnreadMessagesSync(); - - // Mark unread messages as read when they are in the current chat - readCurrentChat(); - - // Update UI - SwingUtilities - .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); - }).start(); - }).start(); - } - - private void updateUserStates() { - for (int i = 0; i < userList.getModel().getSize(); i++) - for (int j = 0; j < localDB.getChats().size(); j++) - if (userList.getModel().getElementAt(i).getID() == localDB.getChats().get(j).getRecipient().getID()) - userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); - } - - /** - * Marks messages in the current chat as {@code READ}. - */ - private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } -} +package envoy.client.ui; + +import java.awt.Color; +import java.awt.ComponentOrientation; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextPane; +import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.border.EmptyBorder; + +import envoy.client.Chat; +import envoy.client.Client; +import envoy.client.Config; +import envoy.client.LocalDB; +import envoy.schema.Message; +import envoy.schema.Sync; +import envoy.schema.User; + +/** + * Project: envoy-client
+ * File: ChatWindow.java
+ * Created: 28 Sep 2019
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @author Leon Hofmeister + * @since Envoy v0.1-alpha + */ +public class ChatWindow extends JFrame { + + private static final long serialVersionUID = 6865098428255463649L; + + private JPanel contentPane = new JPanel(); + + private Client client; + private LocalDB localDB; + + private JList userList = new JList<>(); + private Chat currentChat; + + private JTextArea messageEnterTextArea; + + private static final Logger logger = Logger.getLogger(ChatWindow.class.getSimpleName()); + + public ChatWindow(Client client, LocalDB localDB) { + this.client = client; + this.localDB = localDB; + + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(100, 100, 600, 800); + setTitle("Envoy"); + setLocationRelativeTo(null); + + // Save chats when window closes + addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent evt) { + try { + localDB.saveToLocalDB(); + } catch (IOException e1) { + e1.printStackTrace(); + logger.log(Level.WARNING, "Unable to save the messages", e1); + } + } + }); + + contentPane.setBackground(new Color(0, 0, 0)); + contentPane.setForeground(Color.white); + contentPane.setBorder(new EmptyBorder(0, 5, 0, 0)); + setContentPane(contentPane); + GridBagLayout gbl_contentPane = new GridBagLayout(); + gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; + gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; + gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; + gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 }; + contentPane.setLayout(gbl_contentPane); + + JList messageList = new JList<>(); + messageList.setCellRenderer(new MessageListRenderer()); + + messageList.setFocusTraversalKeysEnabled(false); + messageList.setSelectionForeground(new Color(255, 255, 255)); + messageList.setSelectionBackground(new Color(102, 0, 153)); + messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + messageList.setForeground(new Color(255, 255, 255)); + messageList.setBackground(new Color(51, 51, 51)); + + DefaultListModel messageListModel = new DefaultListModel<>(); + messageList.setModel(messageListModel); + messageList.setFont(new Font("Arial", Font.PLAIN, 17)); + messageList.setFixedCellHeight(60); + messageList.setBorder(new EmptyBorder(5, 5, 5, 5)); + + JScrollPane scrollPane = new JScrollPane(); + scrollPane.setForeground(new Color(0, 0, 0)); + scrollPane.setBackground(new Color(51, 51, 51)); + scrollPane.setViewportView(messageList); + scrollPane.setBorder(null); + + GridBagConstraints gbc_scrollPane = new GridBagConstraints(); + gbc_scrollPane.fill = GridBagConstraints.BOTH; + gbc_scrollPane.gridwidth = 2; + gbc_scrollPane.gridx = 1; + gbc_scrollPane.gridy = 1; + + gbc_scrollPane.insets = new Insets(0, 10, 10, 10); + + contentPane.add(scrollPane, gbc_scrollPane); + + // Message enter field + messageEnterTextArea = new JTextArea(); + messageEnterTextArea.addKeyListener(new KeyAdapter() { + + @Override + public void keyReleased(KeyEvent e) { + + if (e.getKeyCode() == KeyEvent.VK_ENTER + && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + + postMessage(messageList); + } + + } + }); + // Checks for changed Message + messageEnterTextArea.setWrapStyleWord(true); + messageEnterTextArea.setCaretColor(new Color(255, 255, 255)); + messageEnterTextArea.setForeground(new Color(255, 255, 255)); + messageEnterTextArea.setBackground(new Color(51, 51, 51)); + messageEnterTextArea.setLineWrap(true); + messageEnterTextArea.setBorder(null); + messageEnterTextArea.setFont(new Font("Arial", Font.PLAIN, 17)); + messageEnterTextArea.setBorder(new EmptyBorder(5, 5, 5, 5)); + + GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); + gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; + gbc_messageEnterTextfield.gridx = 1; + gbc_messageEnterTextfield.gridy = 2; + + gbc_messageEnterTextfield.insets = new Insets(10, 10, 10, 10); + + contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); + + // Post Button + JButton postButton = new JButton("Post"); + postButton.setForeground(new Color(255, 255, 255)); + postButton.setBackground(new Color(102, 51, 153)); + postButton.setBorderPainted(false); + + GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); + + gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; + gbc_moveSelectionPostButton.gridx = 2; + gbc_moveSelectionPostButton.gridy = 2; + + gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); + + postButton.addActionListener((evt) -> { postMessage(messageList); }); + contentPane.add(postButton, gbc_moveSelectionPostButton); + + // Settings Button + JButton settingsButton = new JButton("Settings"); + settingsButton.setForeground(new Color(255, 255, 255)); + settingsButton.setBackground(new Color(102, 51, 153)); + settingsButton.setBorderPainted(false); + + GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); + + gbc_moveSelectionSettingsButton.fill = GridBagConstraints.BOTH; + gbc_moveSelectionSettingsButton.gridx = 2; + gbc_moveSelectionSettingsButton.gridy = 0; + + gbc_moveSelectionSettingsButton.insets = new Insets(10, 10, 10, 10); + + settingsButton.addActionListener((evt) -> { + try { + SettingsScreen.open(localDB.getUser().getName()); + } catch (Exception e) { + SettingsScreen.open(); + logger.log(Level.WARNING, "An error occured while opening the settings screen", e); + e.printStackTrace(); + } + }); + contentPane.add(settingsButton, gbc_moveSelectionSettingsButton); + + // Partner name display + JTextPane textPane = new JTextPane(); + textPane.setBackground(new Color(0, 0, 0)); + textPane.setForeground(new Color(255, 255, 255)); + + textPane.setFont(new Font("Arial", Font.PLAIN, 20)); + + GridBagConstraints gbc_partnerName = new GridBagConstraints(); + gbc_partnerName.fill = GridBagConstraints.HORIZONTAL; + gbc_partnerName.gridx = 1; + gbc_partnerName.gridy = 0; + + gbc_partnerName.insets = new Insets(0, 10, 0, 10); + contentPane.add(textPane, gbc_partnerName); + + userList.setCellRenderer(new UserListRenderer()); + userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + userList.addListSelectionListener((listSelectionEvent) -> { + if (!listSelectionEvent.getValueIsAdjusting()) { + @SuppressWarnings("unchecked") + final JList selectedUserList = (JList) listSelectionEvent.getSource(); + final User user = selectedUserList.getSelectedValue(); + client.setRecipient(user); + + currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); + + // Set all unread messages in the chat to read + readCurrentChat(); + + client.setRecipient(user); + + textPane.setText(currentChat.getRecipient().getName()); + + messageList.setModel(currentChat.getModel()); + contentPane.revalidate(); + } + }); + + userList.setSelectionForeground(new Color(255, 255, 255)); + userList.setSelectionBackground(new Color(102, 0, 153)); + userList.setForeground(new Color(255, 255, 255)); + userList.setBackground(new Color(51, 51, 51)); + userList.setFont(new Font("Arial", Font.PLAIN, 17)); + userList.setBorder(new EmptyBorder(5, 5, 5, 5)); + + GridBagConstraints gbc_userList = new GridBagConstraints(); + gbc_userList.fill = GridBagConstraints.VERTICAL; + gbc_userList.gridx = 0; + gbc_userList.gridy = 1; + gbc_userList.anchor = GridBagConstraints.PAGE_START; + gbc_userList.insets = new Insets(0, 0, 10, 0); + + contentPane.add(userList, gbc_userList); + contentPane.revalidate(); + + loadUsersAndChats(); + startSyncThread(Config.getInstance().getSyncTimeout()); + + contentPane.revalidate(); + } + + private void postMessage(JList messageList) { + if (!client.hasRecipient()) { + JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); + } + + if (!messageEnterTextArea.getText().isEmpty()) try { + + // Create and send message object + final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient()); + currentChat.appendMessage(message); + messageList.setModel(currentChat.getModel()); + + // Clear text field + messageEnterTextArea.setText(""); + contentPane.revalidate(); + } catch (Exception e) { + JOptionPane.showMessageDialog(this, + "An exception occured while sending a message. See the log for more details.", + "Exception occured", + JOptionPane.ERROR_MESSAGE); + e.printStackTrace(); + } + } + + /** + * Initializes the elements of the user list by downloading them from the + * server. + * + * @since Envoy v0.1-alpha + */ + private void loadUsersAndChats() { + new Thread(() -> { + Sync users = client.getUsersListXml(); + DefaultListModel userListModel = new DefaultListModel<>(); + users.getUsers().forEach(user -> { + userListModel.addElement(user); + + // Check if user exists in local DB + if (localDB.getChats().stream().filter(c -> c.getRecipient().getID() == user.getID()).count() == 0) + localDB.getChats().add(new Chat(user)); + }); + SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); + }).start(); + } + + /** + * Updates the data model and the UI repeatedly after a certain amount of + * time. + * + * @param timeout the amount of time that passes between two requests sent to + * the server + * @since Envoy v0.1-alpha + */ + private void startSyncThread(int timeout) { + new Timer(timeout, (evt) -> { + new Thread(() -> { + + // Synchronize + localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + + // Process unread messages + localDB.addUnreadMessagesToLocalDB(); + localDB.clearUnreadMessagesSync(); + + // Mark unread messages as read when they are in the current chat + readCurrentChat(); + + // Update UI + SwingUtilities.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); + }).start(); + }).start(); + } + + private void updateUserStates() { + for (int i = 0; i < userList.getModel().getSize(); i++) + for (int j = 0; j < localDB.getChats().size(); j++) + if (userList.getModel().getElementAt(i).getID() == localDB.getChats().get(j).getRecipient().getID()) + userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); + } + + /** + * Marks messages in the current chat as {@code READ}. + */ + private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } +} diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 9053c6c..3e6eb23 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -1,54 +1,49 @@ -package envoy.client.ui; - -import java.awt.Component; -import java.text.SimpleDateFormat; - -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.ListCellRenderer; - -import envoy.schema.Message; - -/** - * Defines how a message is displayed.
- *
- * - * Project: envoy-client
- * File: UserListRenderer.java
- * Created: 19 Oct 2019
- * - * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @since Envoy v0.1-alpha - */ -public class MessageListRenderer extends JLabel implements ListCellRenderer { - - private static final long serialVersionUID = 5164417379767181198L; - - @Override - public Component getListCellRendererComponent(JList list, Message value, int index, - boolean isSelected, boolean cellHasFocus) { - if (isSelected) { - setBackground(list.getSelectionBackground()); - setForeground(list.getSelectionForeground()); - } else { - setBackground(list.getBackground()); - setForeground(list.getForeground()); - } - - setOpaque(true); - - final String text = value.getContent().get(0).getText(); - final String state = value.getMetadata().getState().toString(); - final String date = value.getMetadata().getDate() == null ? "" - : new SimpleDateFormat("dd.MM.yyyy HH:mm ") - .format(value.getMetadata().getDate().toGregorianCalendar().getTime()); - - setText(String.format( - "

%s

%s :%s", - date, - text, - state)); - return this; - } +package envoy.client.ui; + +import java.awt.Component; +import java.text.SimpleDateFormat; + +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +import envoy.schema.Message; + +/** + * Defines how a message is displayed.
+ *
+ * + * Project: envoy-client
+ * File: UserListRenderer.java
+ * Created: 19 Oct 2019
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.1-alpha + */ +public class MessageListRenderer extends JLabel implements ListCellRenderer { + + private static final long serialVersionUID = 5164417379767181198L; + + @Override + public Component getListCellRendererComponent(JList list, Message value, int index, boolean isSelected, boolean cellHasFocus) { + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + setOpaque(true); + + final String text = value.getContent().get(0).getText(); + final String state = value.getMetadata().getState().toString(); + final String date = value.getMetadata().getDate() == null ? "" + : new SimpleDateFormat("dd.MM.yyyy HH:mm ").format(value.getMetadata().getDate().toGregorianCalendar().getTime()); + + setText(String + .format("

%s

%s :%s", date, text, state)); + return this; + } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index 7d5de28..08aa9cb 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -41,7 +41,6 @@ public class SettingsScreen extends JDialog { * It personalises the screen more. * * @param username The name of the User - * @param Email The Email that is associated with that Account * @since Envoy v0.1-alpha */ public static void open(String username) {// , String Email) {AUSKLAMMERN, WENN ANMELDUNG PER @@ -101,7 +100,6 @@ public class SettingsScreen extends JDialog { * It personalises the screen more. * * @param Username The name of the User - * @param Email The Email that is associated with that Account * @since Envoy v0.1-alpha */ public SettingsScreen(String Username) {// , String Email, String hashedPwd) {AUSKLAMMERN, WENN ANMELDUNG PER EMAIL @@ -145,10 +143,10 @@ public class SettingsScreen extends JDialog { public static boolean isEnterToSend() { return enterToSend; } /** - * @param enterToSend
- * toggles whether a message should be sent via - *
- * buttonpress "enter" or "ctrl"+"enter" + * @param enterForSend
+ * toggles whether a message should be sent via + *
+ * buttonpress "enter" or "ctrl"+"enter" * @since Envoy v0.1-alpha */ public static void setEnterToSend(boolean enterForSend) { enterToSend = enterForSend; } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 4d6a198..5b8674f 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -26,11 +26,11 @@ import envoy.exception.EnvoyException; */ public class Startup { - private static final Logger logger = Logger.getLogger(Client.class.getSimpleName()); - + private static final Logger logger = Logger.getLogger(Startup.class.getSimpleName()); + public static void main(String[] args) { logger.setLevel(Level.ALL); - + Config config = Config.getInstance(); // Load the configuration from client.properties first @@ -44,30 +44,29 @@ public class Startup { } // Override configuration values with command line arguments - if (args.length > 0) - config.load(args); + if (args.length > 0) config.load(args); if (!config.isInitialized()) { - logger.warning("Server or port are not defined. Exiting..."); - JOptionPane.showMessageDialog(null, "Error loading configuration values.", "Configuration error", - JOptionPane.ERROR_MESSAGE); + logger.severe("Server or port are not defined. Exiting..."); + JOptionPane.showMessageDialog(null, "Error loading configuration values.", "Configuration error", JOptionPane.ERROR_MESSAGE); System.exit(1); } String userName = JOptionPane.showInputDialog("Please enter your username"); if (userName == null || userName.isEmpty()) { - logger.warning("User name is not set or empty. Exiting..."); + logger.severe("User name is not set or empty. Exiting..."); System.exit(1); } - Client client = new Client(config, userName); - LocalDB localDB = new LocalDB(client.getSender()); + Client client = new Client(config, userName); + LocalDB localDB = new LocalDB(client.getSender()); try { localDB.initializeDBFile(config.getLocalDB()); } catch (EnvoyException e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", - "Local DB error", JOptionPane.WARNING_MESSAGE); + "Local DB error", + JOptionPane.WARNING_MESSAGE); } EventQueue.invokeLater(() -> { diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index 40bb2ad..e794b1f 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -1,65 +1,56 @@ -package envoy.client.ui; - -import java.awt.Component; - -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.ListCellRenderer; - -import envoy.schema.User; -import envoy.schema.User.UserStatus; - -/** - * Defines how the {@code UserList} is displayed. - * - * Project: envoy-client
- * File: UserListRenderer.java
- * Created: 12 Oct 2019
- * - * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @since Envoy v0.1-alpha - */ -public class UserListRenderer extends JLabel implements ListCellRenderer { - - private static final long serialVersionUID = 5164417379767181198L; - - @Override - public Component getListCellRendererComponent(JList list, User value, int index, boolean isSelected, - boolean cellHasFocus) { - if (isSelected) { - setBackground(list.getSelectionBackground()); - setForeground(list.getSelectionForeground()); - } else { - setBackground(list.getBackground()); - setForeground(list.getForeground()); - } - - // Enable background rendering - setOpaque(true); - - - final String name = value.getName(); - final UserStatus status = value.getStatus(); - - switch (status) { - case ONLINE: - setText(String.format( - "

%s

%s", - status, - name)); - break; - - case OFFLINE: - setText(String.format( - "

%s

%s", - status, - name)); - break; - } - - - - return this; - } +package envoy.client.ui; + +import java.awt.Component; + +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +import envoy.schema.User; +import envoy.schema.User.UserStatus; + +/** + * Defines how the {@code UserList} is displayed. + * + * Project: envoy-client
+ * File: UserListRenderer.java
+ * Created: 12 Oct 2019
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.1-alpha + */ +public class UserListRenderer extends JLabel implements ListCellRenderer { + + private static final long serialVersionUID = 5164417379767181198L; + + @SuppressWarnings("incomplete-switch") + @Override + public Component getListCellRendererComponent(JList list, User value, int index, boolean isSelected, boolean cellHasFocus) { + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + // Enable background rendering + setOpaque(true); + + final String name = value.getName(); + final UserStatus status = value.getStatus(); + + switch (status) { + case ONLINE: + setText(String + .format("

%s

%s", status, name)); + break; + case OFFLINE: + setText(String + .format("

%s

%s", status, name)); + break; + } + return this; + } } \ No newline at end of file From 860d2b0dcf4c75d23a379fdaa8e1331e5ba0e555 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 7 Dec 2019 10:58:03 +0100 Subject: [PATCH 088/474] Themes & Themes Configuration Added themes to choose from and provides customization setting for these. --- src/main/java/envoy/client/Settings.java | 76 ++- src/main/java/envoy/client/ui/ChatWindow.java | 91 ++-- .../envoy/client/ui/MessageListRenderer.java | 28 +- .../java/envoy/client/ui/SettingsScreen.java | 500 ++++++++++++++++-- src/main/java/envoy/client/ui/Theme.java | 121 +++++ src/main/java/envoy/client/ui/UIColors.java | 123 ----- .../envoy/client/ui/UserListRenderer.java | 29 +- 7 files changed, 736 insertions(+), 232 deletions(-) create mode 100644 src/main/java/envoy/client/ui/Theme.java delete mode 100644 src/main/java/envoy/client/ui/UIColors.java diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 76d8ce3..fa6088f 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -1,7 +1,11 @@ package envoy.client; +import java.awt.Color; +import java.util.HashMap; +import java.util.Map; import java.util.prefs.Preferences; +import envoy.client.ui.Theme; import envoy.schema.User; /** @@ -10,14 +14,17 @@ import envoy.schema.User; * Created: 11 Nov 2019
* * @author Leon Hofmeister + * @author Maximilian Käfer * @since Envoy v0.2-alpha */ public class Settings { - private String username; - private String email; - private boolean enterToSend = true; - private boolean darkMode = true; + private String username; + private String email; + private boolean enterToSend = true; + private Map themes = new HashMap<>(); + + private String currentTheme; // private Image profilePic; private static Settings settings; private Preferences prefs = Preferences.userNodeForPackage(Settings.class); @@ -47,24 +54,54 @@ public class Settings { public void load() { settings.setUsername(prefs.get("username", "")); settings.setEmail(prefs.get("email", "")); - settings.setDarkMode(prefs.getBoolean("darkMode", true)); settings.setEnterToSend(prefs.getBoolean("enterToSend", true)); + // currentTheme = "dark"; Activate once if NullPointerException on currentTheme + // and change theme to dark or white in Settings + settings.setCurrentTheme(prefs.get("theme", "dark")); } public void save() { prefs.put("username", settings.getUsername()); prefs.put("email", settings.getEmail()); - prefs.putBoolean("darkMode", settings.isDarkMode()); + prefs.put("theme", currentTheme); + System.out.println(currentTheme); prefs.putBoolean("enterToSend", settings.isEnterToSend()); + // TODO: override themes map + } - + public void firstSave(User user) { + + // TODO: load themes + + settings.getThemes() + .put("dark", + new Theme("dark", Color.black, Color.darkGray, Color.white, Color.blue, Color.white, Color.orange, + Color.blue, Color.white, Color.white)); + settings.getThemes() + .put("light", + new Theme("light", new Color(235, 235, 235), Color.white, Color.white, Color.darkGray, Color.black, + Color.orange, Color.darkGray, Color.black, Color.black)); + + + + + prefs.put("username", user.getName()); -// prefs.put("email", user.getEmail()); -// prefs.putBoolean("darkMode", true); -// prefs.putBoolean("enterToSend", true); + // prefs.put("email", user.getEmail()); + // prefs.putBoolean("darkMode", true); + // prefs.putBoolean("enterToSend", true); } + public void addNewThemeToMap(Theme theme) { + settings.getThemes().put(theme.getThemeName(), theme); + currentTheme = theme.getThemeName(); + } + + public String getCurrentTheme() { return currentTheme; } + + public void setCurrentTheme(String themeName) { currentTheme = themeName; } + /** * @return the username * @since Envoy v0.2-alpha @@ -105,23 +142,9 @@ public class Settings { */ public void setEnterToSend(boolean enterToSend) { this.enterToSend = enterToSend; } - /** - * Describes whether the Envoy GUI should be displayed in dark mode or not. - * - * @return true, if dark mode display is currently set, else the light theme - * will be displayed - * @since Envoy v0.2-alpha - */ - public boolean isDarkMode() { return darkMode; } + public Map getThemes() { return themes; } - /** - * Change display mode of Envoy GUI. - * - * @param darkMode true, if dark mode display is currently set,
- * else the light theme will be displayed - * @since Envoy v0.2-alpha - */ - public void setDarkMode(boolean darkMode) { this.darkMode = darkMode; } + public void setThemes(Map themes) { this.themes = themes; } // /** // * @return the profilePic @@ -135,4 +158,5 @@ public class Settings { // */ // public void setProfilePic(Image profilePic) { this.profilePic = profilePic; } + } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 38634ea..e0ea09b 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -49,10 +49,8 @@ public class ChatWindow extends JFrame { private static final long serialVersionUID = 6865098428255463649L; // user specific objects - private Client client; - private LocalDB localDB; - // used colors in Envoy - private UIColors uiColors = UIColors.getInstance(true); + private Client client; + private LocalDB localDB; // GUI components private JPanel contentPane = new JPanel(); private JTextArea messageEnterTextArea = new JTextArea(); @@ -62,8 +60,8 @@ public class ChatWindow extends JFrame { private JScrollPane scrollPane = new JScrollPane(); private JTextPane textPane = new JTextPane(); // private JCheckBox jCbChangeMode; - private JButton postButton = new JButton("Post"); - private JButton settingsButton = new JButton("Settings"); + private JButton postButton = new JButton("Post"); + private JButton settingsButton = new JButton("Settings"); private static int space = 4; @@ -80,12 +78,14 @@ public class ChatWindow extends JFrame { addWindowListener(new WindowAdapter() { @Override - public void windowClosing(WindowEvent e) { try { - localDB.saveToLocalDB(); - } catch (IOException e1) { - e1.printStackTrace(); - System.err.println("Could nnot save localDB"); - } } + public void windowClosing(WindowEvent e) { + try { + localDB.saveToLocalDB(); + } catch (IOException e1) { + e1.printStackTrace(); + System.err.println("Could not save localDB"); + } + } }); contentPane.setBorder(new EmptyBorder(space, space, space, space)); @@ -125,8 +125,9 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) - || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + if (e.getKeyCode() == KeyEvent.VK_ENTER + && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) + || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); } @@ -176,7 +177,9 @@ public class ChatWindow extends JFrame { settingsButton.addActionListener((evt) -> { try { SettingsScreen.open(); - changeChatWindowColors(); + + changeChatWindowColors(Settings.getInstance().getCurrentTheme()); + } catch (Exception e) { System.err.println("An error occured while opening the settings screen: " + e); e.printStackTrace(); @@ -232,8 +235,8 @@ public class ChatWindow extends JFrame { gbc_userList.anchor = GridBagConstraints.PAGE_START; gbc_userList.insets = new Insets(space, space, space, space); - changeChatWindowColors(); - + changeChatWindowColors(Settings.getInstance().getCurrentTheme()); + contentPane.add(userList, gbc_userList); contentPane.revalidate(); @@ -243,43 +246,44 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); } + /** * Used to immediately reload the ChatWindow when settings were changed. * * @since Envoy v0.1-alpha */ - public void changeChatWindowColors() { - uiColors.setDisplayMode(Settings.getInstance().isDarkMode()); + public void changeChatWindowColors(String key) { + Theme theme = Settings.getInstance().getThemes().get(key); // contentPane - contentPane.setBackground(uiColors.getBackgroundColor()); - contentPane.setForeground(uiColors.getTextColor()); + contentPane.setBackground(theme.getBackgroundColor()); + contentPane.setForeground(theme.getUserNameColor()); // messageList - messageList.setSelectionForeground(uiColors.getTextColor()); - messageList.setSelectionBackground(uiColors.getSpecialUseColor()); - messageList.setForeground(uiColors.getTextColor()); - messageList.setBackground(uiColors.getUserInteractionColor()); + messageList.setSelectionForeground(theme.getUserNameColor()); + messageList.setSelectionBackground(theme.getSelectionColor()); + messageList.setForeground(theme.getMessageColorChat()); + messageList.setBackground(theme.getCellColor()); // scrollPane - scrollPane.setForeground(uiColors.getBackgroundColor()); - scrollPane.setBackground(uiColors.getUserInteractionColor()); + scrollPane.setForeground(theme.getBackgroundColor()); + scrollPane.setBackground(theme.getCellColor()); // messageEnterTextArea - messageEnterTextArea.setCaretColor(uiColors.getTextColor()); - messageEnterTextArea.setForeground(uiColors.getTextColor()); - messageEnterTextArea.setBackground(uiColors.getUserInteractionColor()); + messageEnterTextArea.setCaretColor(theme.getTypingMessageColor()); + messageEnterTextArea.setForeground(theme.getTypingMessageColor()); + messageEnterTextArea.setBackground(theme.getCellColor()); // postButton - postButton.setForeground(uiColors.getTextColor()); - postButton.setBackground(uiColors.getSpecialUseColor()); + postButton.setForeground(theme.getInteractableForegroundColor()); + postButton.setBackground(theme.getInteractableBackgroundColor()); // settingsButton - settingsButton.setForeground(uiColors.getTextColor()); - settingsButton.setBackground(uiColors.getSpecialUseColor()); + settingsButton.setForeground(theme.getInteractableForegroundColor()); + settingsButton.setBackground(theme.getInteractableBackgroundColor()); // textPane - textPane.setBackground(uiColors.getBackgroundColor()); - textPane.setForeground(uiColors.getTextColor()); + textPane.setBackground(theme.getBackgroundColor()); + textPane.setForeground(theme.getUserNameColor()); // userList - userList.setSelectionForeground(uiColors.getTextColor()); - userList.setSelectionBackground(uiColors.getSpecialUseColor()); - userList.setForeground(uiColors.getTextColor()); - userList.setBackground(uiColors.getUserInteractionColor()); + userList.setSelectionForeground(theme.getUserNameColor()); + userList.setSelectionBackground(theme.getSelectionColor()); + userList.setForeground(theme.getUserNameColor()); + userList.setBackground(theme.getCellColor()); } @@ -293,9 +297,10 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { - // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient().getID()); - localDB.addWaitingMessageToLocalDB(message, currentChat); + // Create and send message object + final Message message = localDB.createMessage(messageEnterTextArea.getText(), + currentChat.getRecipient().getID()); + localDB.addWaitingMessageToLocalDB(message, currentChat); messageList.setModel(currentChat.getModel()); // Clear text field diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 9053c6c..ec2aaab 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -1,5 +1,6 @@ package envoy.client.ui; +import java.awt.Color; import java.awt.Component; import java.text.SimpleDateFormat; @@ -7,6 +8,7 @@ import javax.swing.JLabel; import javax.swing.JList; import javax.swing.ListCellRenderer; +import envoy.client.Settings; import envoy.schema.Message; /** @@ -39,16 +41,38 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer

%s

%s :%s", + "

%s

%s :%s", + dateColor, date, + textColor, text, state)); + return this; } + + public String toHex(Color c) { + int r = c.getRed(); + int g = c.getGreen(); + int b = c.getBlue(); + String hex = String.format("#%02x%02x%02x", r, g, b); + return hex; + } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index 56730aa..80d4927 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -1,15 +1,29 @@ package envoy.client.ui; import java.awt.BorderLayout; -import java.awt.FlowLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.Arrays; +import javax.swing.BoxLayout; +import javax.swing.DefaultListModel; import javax.swing.JButton; +import javax.swing.JColorChooser; +import javax.swing.JComboBox; import javax.swing.JDialog; +import javax.swing.JList; +import javax.swing.JOptionPane; import javax.swing.JPanel; -import javax.swing.border.EmptyBorder; +import javax.swing.JTextPane; +import javax.swing.ListSelectionModel; import envoy.client.Settings; @@ -21,15 +35,36 @@ import envoy.client.Settings; * Created: 31 Oct 2019
* * @author Leon Hofmeister + * @author Maximilian Käfer */ public class SettingsScreen extends JDialog { - private static final long serialVersionUID = -4476913491263077107L; - private final JPanel contentPanel = new JPanel(); - private JPanel buttonPane = new JPanel(); - private JButton okButton = new JButton("Save"); - private JButton cancelButton = new JButton("Cancel"); - private static int space = 5; + private static final long serialVersionUID = -4476913491263077107L; + private final JPanel contentPanel = new JPanel(); + + private DefaultListModel optionsListModel = new DefaultListModel<>(); + private final JList options = new JList(); + private JPanel buttonPane = new JPanel(); + + private JPanel themeContent = new JPanel(); + private String[] themeArray = { Settings.getInstance().getThemes().get("dark").getThemeName(), + Settings.getInstance().getThemes().get("light").getThemeName() }; + private JComboBox themes = new JComboBox(themeArray); + + private GridBagConstraints gbc_themeContent = new GridBagConstraints(); + + private Theme selectedTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + + private JButton createNewThemeButton = new JButton("Create New Theme"); + + private JPanel colorsPanel = new JPanel(); + private JButton okButton = new JButton("Save"); + private JButton cancelButton = new JButton("Cancel"); + private static int space = 5; + + private boolean colorChanged = false; + + private Theme temporaryTheme; private static SettingsScreen settingsScreen; // TODO: Add a JPanel with all the Information necessary: @@ -44,7 +79,7 @@ public class SettingsScreen extends JDialog { */ public static void open() { - UIColors.getInstance(Settings.getInstance().isDarkMode()); + // UIColors.getInstance(Settings.getInstance().isDarkMode()); settingsScreen = new SettingsScreen(); settingsScreen.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); settingsScreen.setModal(true); @@ -58,21 +93,254 @@ public class SettingsScreen extends JDialog { */ private SettingsScreen() { - setBounds(100, 100, 450, 300); + System.out.println(Settings.getInstance().getCurrentTheme()); + + setBounds(10, 10, 450, 650); getContentPane().setLayout(new BorderLayout()); - contentPanel.setLayout(new FlowLayout()); - contentPanel.setBorder(new EmptyBorder(space, space, space, space)); - getContentPane().add(contentPanel, BorderLayout.CENTER); { - getContentPane().add(buttonPane, BorderLayout.SOUTH); + + createNewThemeButton.setEnabled(false); + + temporaryTheme = new Theme("temporaryTheme", + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + // ContentPane------------------------------------------------------ + GridBagLayout gbl_contentPanel = new GridBagLayout(); + + gbl_contentPanel.columnWidths = new int[] { 1, 1 }; + gbl_contentPanel.rowHeights = new int[] { 1 }; + gbl_contentPanel.columnWeights = new double[] { 0.05, 1.0 }; + gbl_contentPanel.rowWeights = new double[] { 1.0 }; + + getContentPane().add(contentPanel, BorderLayout.CENTER); + contentPanel.setLayout(gbl_contentPanel); + + options.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + options.addListSelectionListener((listSelectionEvent) -> { + if (!listSelectionEvent.getValueIsAdjusting()) { + @SuppressWarnings("unchecked") + final JList selectedOption = (JList) listSelectionEvent.getSource(); + final String option = selectedOption.getSelectedValue(); + System.out.println(option); + + switch (option) { + case "Color Themes": + setContent(themeContent, gbc_themeContent); + getContentPane().repaint(); + getContentPane().revalidate(); + break; + } + } + }); + + options.setFont(new Font("Arial", Font.PLAIN, 14)); + + Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + + options.setSelectionForeground(theme.getUserNameColor()); + options.setSelectionBackground(theme.getSelectionColor()); + options.setForeground(theme.getUserNameColor()); + options.setBackground(theme.getCellColor()); + + GridBagConstraints gbc_optionsList = new GridBagConstraints(); + gbc_optionsList.fill = GridBagConstraints.BOTH; + gbc_optionsList.gridx = 0; + gbc_optionsList.gridy = 0; + gbc_optionsList.anchor = GridBagConstraints.PAGE_START; + gbc_optionsList.insets = new Insets(space, space, space, space); + + optionsListModel.addElement("Color Themes"); + + options.setModel(optionsListModel); + + contentPanel.add(options, gbc_optionsList); + + // ThemeContent --- + + gbc_themeContent = new GridBagConstraints(); + gbc_themeContent.fill = GridBagConstraints.BOTH; + gbc_themeContent.gridx = 1; + gbc_themeContent.gridy = 0; + gbc_themeContent.anchor = GridBagConstraints.PAGE_START; + gbc_themeContent.insets = new Insets(space, space, space, space); + + GridBagLayout gbl_themeLayout = new GridBagLayout(); + + // themeContent.setSelectionForeground(theme.getUserNameColor()); + // themeContent.setSelectionBackground(theme.getSelectionColor()); + themeContent.setForeground(theme.getUserNameColor()); + themeContent.setBackground(theme.getCellColor()); + + gbl_themeLayout.columnWidths = new int[] { 1, 1 }; + gbl_themeLayout.rowHeights = new int[] { 1, 1 }; + gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 }; + gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0 }; + + themeContent.setLayout(gbl_themeLayout); + + themes.setBackground(theme.getUserNameColor()); + themes.setForeground(theme.getBackgroundColor()); + themes.setSelectedItem(Settings.getInstance().getCurrentTheme()); + // themes.setBorder(null); + + themes.addItemListener(new ItemListener() { + + @Override + public void itemStateChanged(ItemEvent e) { + String selectedValue = (String) themes.getSelectedItem(); + System.out.println(selectedValue); + selectedTheme = Settings.getInstance().getThemes().get(selectedValue); + } + + }); + + GridBagConstraints gbc_themes = new GridBagConstraints(); + gbc_themes.fill = GridBagConstraints.HORIZONTAL; + gbc_themes.gridx = 0; + gbc_themes.gridy = 0; + gbc_themes.anchor = GridBagConstraints.NORTHWEST; + gbc_themes.insets = new Insets(space, space, space, space); + + themeContent.add(themes, gbc_themes); + + colorsPanel.setLayout((LayoutManager) new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); + colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getBackgroundColor(), + "Background", + 1); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getCellColor(), + "Cells", + 2); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getInteractableForegroundColor(), + "Interactable Foreground", + 3); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getInteractableBackgroundColor(), + "Interactable Background", + 4); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getMessageColorChat(), + "Messages Chat", + 5); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getDateColorChat(), + "Date Chat", + 6); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getSelectionColor(), + "Selection", + 7); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getTypingMessageColor(), + "Typing Message", + 8); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getUserNameColor(), + "User Names", + 9); + + GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); + gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; + gbc_colorsPanel.gridx = 0; + gbc_colorsPanel.gridy = 1; + gbc_colorsPanel.gridwidth = 2; + gbc_colorsPanel.anchor = GridBagConstraints.NORTHWEST; + gbc_colorsPanel.insets = new Insets(space, 0, 0, 0); + + themeContent.add(colorsPanel, gbc_colorsPanel); + + createNewThemeButton.setBackground(theme.getInteractableBackgroundColor()); + createNewThemeButton.setForeground(theme.getInteractableForegroundColor()); + colorsPanel.setBackground(theme.getCellColor()); + + createNewThemeButton.addActionListener((evt) -> { + try { + String s = JOptionPane.showInputDialog("Enter a name for the new theme"); + System.out.println(s); + Settings.getInstance() + .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), + temporaryTheme.getCellColor(), temporaryTheme.getInteractableForegroundColor(), + temporaryTheme.getInteractableBackgroundColor(), temporaryTheme.getMessageColorChat(), + temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), + temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor())); + themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); + themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName(); + + temporaryTheme = new Theme("temporaryTheme", + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + + createNewThemeButton.setEnabled(false); + themes.addItem(themeArray[themeArray.length - 1]); + + contentPanel.revalidate(); + contentPanel.repaint(); + + // TODO: Create new Theme + + } catch (Exception e) { + System.err.println("New theme couldn't be created! " + e); + e.printStackTrace(); + } + }); + + GridBagConstraints gbc_createNewTheme = new GridBagConstraints(); + gbc_createNewTheme.gridx = 0; + gbc_createNewTheme.gridy = 10; + + colorsPanel.add(createNewThemeButton, gbc_createNewTheme); + + // ButtonPane------------------------------------------------------- GridBagLayout gbl_buttonPane = new GridBagLayout(); gbl_buttonPane.columnWidths = new int[] { 100, 250, 100, 0 }; gbl_buttonPane.rowHeights = new int[] { 25, 0 }; gbl_buttonPane.columnWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE }; gbl_buttonPane.rowWeights = new double[] { 0.0, Double.MIN_VALUE }; + + getContentPane().add(buttonPane, BorderLayout.SOUTH); buttonPane.setLayout(gbl_buttonPane); { cancelButton.setActionCommand("Cancel"); + cancelButton.setBorderPainted(false); GridBagConstraints gbc_cancelButton = new GridBagConstraints(); gbc_cancelButton.anchor = GridBagConstraints.NORTHWEST; gbc_cancelButton.insets = new Insets(space, space, space, space); @@ -84,6 +352,7 @@ public class SettingsScreen extends JDialog { } { okButton.setActionCommand("OK"); + okButton.setBorderPainted(false); GridBagConstraints gbc_okButton = new GridBagConstraints(); gbc_okButton.anchor = GridBagConstraints.NORTHEAST; gbc_okButton.fill = GridBagConstraints.EAST; @@ -95,16 +364,19 @@ public class SettingsScreen extends JDialog { okButton.addActionListener((evt) -> { try { Settings.getInstance().setUsername(Settings.getInstance().getUsername());// still temporary - // value + Settings.getInstance().setEmail(Settings.getInstance().getEmail());// still temporary value - Settings.getInstance().setDarkMode(!Settings.getInstance().isDarkMode());// TODO temporary - // values while no - // UI is implemented + Settings.getInstance().setEnterToSend(Settings.getInstance().isEnterToSend());// still temporary - // value + + Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); + System.out.println(selectedTheme.getThemeName()); + + changeSettingsScreenColors(Settings.getInstance().getCurrentTheme()); + updateColorVariables(Settings.getInstance().getCurrentTheme()); + Settings.getInstance().save(); - UIColors.getUIColors().setDisplayMode(Settings.getInstance().isDarkMode()); - changeSettingsScreenColors(); + revalidate(); repaint(); } catch (Exception e) { @@ -114,23 +386,191 @@ public class SettingsScreen extends JDialog { }); } } - changeSettingsScreenColors(); + changeSettingsScreenColors(Settings.getInstance().getCurrentTheme()); } - private void changeSettingsScreenColors() { + private void changeSettingsScreenColors(String key) { + Theme theme = Settings.getInstance().getThemes().get(key); // whole JDialog - setBackground(UIColors.getUIColors().getBackgroundColor()); + setBackground(theme.getBackgroundColor()); // contentPanel - contentPanel.setBackground(UIColors.getUIColors().getBackgroundColor()); + contentPanel.setBackground(theme.getBackgroundColor()); // buttonPane - buttonPane.setBackground(UIColors.getUIColors().getBackgroundColor()); + buttonPane.setBackground(theme.getCellColor()); // cancelButton - cancelButton.setBackground(UIColors.getUIColors().getSpecialUseColor()); - cancelButton.setForeground(UIColors.getUIColors().getTextColor()); + cancelButton.setBackground(theme.getInteractableBackgroundColor()); + cancelButton.setForeground(theme.getInteractableForegroundColor()); // okButton - okButton.setBackground(UIColors.getUIColors().getSpecialUseColor()); - okButton.setForeground(UIColors.getUIColors().getTextColor()); + okButton.setBackground(theme.getInteractableBackgroundColor()); + okButton.setForeground(theme.getInteractableForegroundColor()); + // options + options.setSelectionForeground(theme.getUserNameColor()); + options.setSelectionBackground(theme.getSelectionColor()); + options.setForeground(theme.getUserNameColor()); + options.setBackground(theme.getCellColor()); + // themeContent + themeContent.setForeground(theme.getUserNameColor()); + themeContent.setBackground(theme.getCellColor()); + // themes + themes.setBackground(theme.getUserNameColor()); + themes.setForeground(theme.getBackgroundColor()); + + createNewThemeButton.setBackground(theme.getInteractableBackgroundColor()); + createNewThemeButton.setForeground(theme.getInteractableForegroundColor()); + colorsPanel.setBackground(theme.getCellColor()); } + public void updateColorVariables(String key) { + Theme theme = Settings.getInstance().getThemes().get(key); + + temporaryTheme = new Theme("temporaryTheme", + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getBackgroundColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor(), + Settings.getInstance() + .getThemes() + .get(Settings.getInstance().getCurrentTheme()) + .getInteractableForegroundColor(), + Settings.getInstance() + .getThemes() + .get(Settings.getInstance().getCurrentTheme()) + .getInteractableBackgroundColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getSelectionColor(), + Settings.getInstance() + .getThemes() + .get(Settings.getInstance().getCurrentTheme()) + .getTypingMessageColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); + + colorsPanel.removeAll(); + + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getBackgroundColor(), + "Background", + 1); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getCellColor(), + "Cells", + 2); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getInteractableForegroundColor(), + "Interactable Foreground", + 3); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getInteractableBackgroundColor(), + "Interactable Background", + 4); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getMessageColorChat(), + "Messages Chat", + 5); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getDateColorChat(), + "Date Chat", + 6); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getSelectionColor(), + "Selection", + 7); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getTypingMessageColor(), + "Typing Message", + 8); + buildCustomizeElement(new JPanel(), + + new JButton(), + new JTextPane(), + theme, + theme.getUserNameColor(), + "User Names", + 9); + + GridBagConstraints gbc_createNewTheme = new GridBagConstraints(); + gbc_createNewTheme.gridx = 0; + gbc_createNewTheme.gridy = 10; + + colorsPanel.add(createNewThemeButton, gbc_createNewTheme); + } + + public void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); } + + public void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, + String name, int yIndex) { + textPane.setFont(new Font("Arial", Font.PLAIN, 14)); + textPane.setBackground(theme.getBackgroundColor()); + textPane.setForeground(theme.getUserNameColor()); + textPane.setText(name); + textPane.setEditable(false); + + button.setBackground(color); + button.setPreferredSize(new Dimension(25, 25)); + + button.addActionListener((evt) -> { + try { + Color newColor = JColorChooser.showDialog(null, "Choose a color", color); + if (newColor.getRGB() != color.getRGB()) { + System.out.println("New Color"); + System.out.println(color.getRGB()); + // TODO: When Theme changed in same settings screen, color variable doesnt + // update. + Color[] colorsArray = temporaryTheme.getAllColors(); + for (int i = 0; i < colorsArray.length; i++) { + if (color.getRGB() == colorsArray[i].getRGB()) { + temporaryTheme.setColor(i, newColor); + colorChanged = true; + createNewThemeButton.setEnabled(true); + break; + } + + } + button.setBackground(newColor); + } + + } catch (Exception e) { + System.err.println("An error occured while opening Color Chooser: " + e); + e.printStackTrace(); + } + }); + + panel.add(textPane); + panel.add(button); + panel.setBackground(theme.getCellColor()); + panel.setAlignmentX(Component.LEFT_ALIGNMENT); + + colorsPanel.add(panel); + } } diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java new file mode 100644 index 0000000..ad8430b --- /dev/null +++ b/src/main/java/envoy/client/ui/Theme.java @@ -0,0 +1,121 @@ +package envoy.client.ui; + +import java.awt.Color; +import java.io.Serializable; + +/** + * + * Project: envoy-client
+ * File: Theme.java
+ * Created: 23 Nov 2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.2-alpha + */ +public class Theme implements Serializable { + + private static final long serialVersionUID = 141727847527060352L; + + private String themeName; + private Color backgroundColor; + private Color cellColor; + private Color interactableBackgroundColor; + private Color userNameColor; + private Color interactableForegroundColor; + private Color messageColorChat; + private Color dateColorChat; + private Color selectionColor; + private Color typingMessageColor; + + public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, + Color interactableBackgroundColor, Color messageColorChat, Color dateColorChat, Color selectionColor, + Color typingMessageColor, Color userNameColor) { + + this.themeName = themeName; + + this.backgroundColor = backgroundColor; + this.cellColor = cellColor; + this.interactableForegroundColor = interactableForegroundColor; + this.interactableBackgroundColor = interactableBackgroundColor; + this.messageColorChat = messageColorChat; + this.dateColorChat = dateColorChat; + this.selectionColor = selectionColor; + this.typingMessageColor = typingMessageColor; + this.userNameColor = userNameColor; + } + + public Theme(String name, Theme other) { + this(name, other.backgroundColor, other.cellColor, other.interactableBackgroundColor, + other.interactableForegroundColor, other.messageColorChat, other.dateColorChat, other.selectionColor, + other.typingMessageColor, other.userNameColor); + } + + public String getThemeName() { return themeName; } + + public Color getInteractableForegroundColor() { return interactableForegroundColor; } + + public Color getMessageColorChat() { return messageColorChat; } + + public Color getDateColorChat() { return dateColorChat; } + + public Color getSelectionColor() { return selectionColor; } + + public Color getTypingMessageColor() { return typingMessageColor; } + + public Color getBackgroundColor() { return backgroundColor; } + + public Color getCellColor() { return cellColor; } + + public Color getInteractableBackgroundColor() { return interactableBackgroundColor; } + + public Color getUserNameColor() { return userNameColor; } + + public Color[] getAllColors() { + Color[] c = new Color[9]; + c[0] = backgroundColor; + c[1] = cellColor; + c[2] = interactableForegroundColor; + c[3] = interactableBackgroundColor; + c[4] = messageColorChat; + c[5] = dateColorChat; + c[6] = selectionColor; + c[7] = typingMessageColor; + c[8] = userNameColor; + + return c; + } + + public void setColor(int index, Color newColor) { + switch (index) { + case 0: + this.backgroundColor = newColor; + break; + case 1: + this.cellColor = newColor; + break; + case 2: + this.interactableForegroundColor = newColor; + break; + case 3: + this.interactableBackgroundColor = newColor; + break; + case 4: + this.messageColorChat = newColor; + break; + case 5: + this.dateColorChat = newColor; + break; + case 6: + this.selectionColor = newColor; + break; + case 7: + this.typingMessageColor = newColor; + break; + case 8: + this.userNameColor = newColor; + break; + + } + } + +} diff --git a/src/main/java/envoy/client/ui/UIColors.java b/src/main/java/envoy/client/ui/UIColors.java deleted file mode 100644 index fdad862..0000000 --- a/src/main/java/envoy/client/ui/UIColors.java +++ /dev/null @@ -1,123 +0,0 @@ -package envoy.client.ui; - -import java.awt.Color; - -/** - * This class stores the colors that are used in Envoy. - *
- *
- * Project: envoy-client
- * File: EnvoyColors.java
- * Created: 16 Nov 2019
- * - * @author Leon Hofmeister - * @since Envoy v0.2-alpha - */ -public class UIColors { - - private UIColors() {} - - private Color backgroundColor; - private Color userInteractionColor; - private Color specialUseColor; - private Color textColor; - private static UIColors uIColors; - - /** - * This method is used to ensure that there is only one instance of EnvoyColors. - * - * @param darkMode default value how envoyColors should be displayed - * @return the instance of EnvoyColors - * @since Envoy v0.2-alpha - */ - public static UIColors getInstance(boolean darkMode) { - if (uIColors == null) { uIColors = new UIColors(); } - uIColors.setDisplayMode(darkMode); - return uIColors; - } - - /** - * Used to change the appearance of Envoy. - * - * @param darkMode if true, Envoy will be displayed in dark mode else it will - * use bright mode - * @since Envoy v0.2-alpha - */ - public void setDisplayMode(boolean darkMode) { - if (darkMode) { - uIColors.setBackgroundColor(Color.black); // TODO: other color suggestions? - uIColors.setUserInteractionColor(Color.darkGray); // temporary - uIColors.setSpecialUseColor(Color.blue); // temporary - uIColors.setTextColor(Color.white); // temporary - - } else { - uIColors.setBackgroundColor(Color.white); // temporary - uIColors.setUserInteractionColor(Color.lightGray); // temporary - uIColors.setSpecialUseColor(Color.green); // temporary - uIColors.setTextColor(Color.black); // temporary - - } - } - - /** - * @return the general background color where no other element overlaps - * @since Envoy v0.2-alpha - */ - public Color getBackgroundColor() { return backgroundColor; } - - /** - * @param backgroundColor the general background where no other element overlaps - * @since Envoy v0.2-alpha - */ - public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } - - /** - * @return the userInteractionColor:
- * This color is used as background for all areas where a user can - * interact with Envoy (i.e. a JTextArea or JList) - * @since Envoy v0.2-alpha - */ - public Color getUserInteractionColor() { return userInteractionColor; } - - /** - * @param userInteractionColor This color is used as background for all areas
- * where a user can interact with Envoy - * (i.e. a JTextArea or JList) - * @since Envoy v0.2-alpha - */ - public void setUserInteractionColor(Color userInteractionColor) { - this.userInteractionColor = userInteractionColor; - } - - /** - * @return specialUseColor: This color is used for any areas that need special attention.
- * (i.e. highlighting a selected list column or a button background) - * @since Envoy v0.2-alpha - */ - public Color getSpecialUseColor() { return specialUseColor; } - - /** - * @param specialUseColor This color is used for any areas that need special attention.
- * (i.e. highlighting a selected list column or a button background) - * @since Envoy v0.2-alpha - */ - public void setSpecialUseColor(Color specialUseColor) { this.specialUseColor = specialUseColor; } - - /** - * @return textColor: The color in which text will be displayed - * @since Envoy v0.2-alpha - */ - public Color getTextColor() { return textColor; } - - /** - * @param textColor The color in which text will be displayed - * @since Envoy v0.2-alpha - */ - public void setTextColor(Color textColor) { this.textColor = textColor; } - - /** - * @return the uiColors object - * @since Envoy v0.2-alpha - */ - public static UIColors getUIColors() { return uIColors; } -} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index a0a2b4e..ef40e3c 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -1,11 +1,13 @@ package envoy.client.ui; +import java.awt.Color; import java.awt.Component; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.ListCellRenderer; +import envoy.client.Settings; import envoy.schema.User; import envoy.schema.User.UserStatus; @@ -24,6 +26,7 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { private static final long serialVersionUID = 5164417379767181198L; + @SuppressWarnings("incomplete-switch") @Override public Component getListCellRendererComponent(JList list, User value, int index, boolean isSelected, boolean cellHasFocus) { @@ -41,31 +44,41 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { final String name = value.getName(); final UserStatus status = value.getStatus(); + + // Getting the UserNameColor of the current theme + String textColor = null; + + textColor = toHex( + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); switch (status) { case ONLINE: setText(String.format( - "

%s

%s", + "

%s

%s", status, + textColor, name)); break; case OFFLINE: setText(String.format( - "

%s

%s", + "

%s

%s", status, + textColor, name)); break; - case AFK: - break; - case DO_NOT_DISTURB: - break; - default: - break; } return this; } + + public String toHex(Color c) { + int r = c.getRed(); + int g = c.getGreen(); + int b = c.getBlue(); + String hex = String.format("#%02x%02x%02x", r, g, b); + return hex; + } } \ No newline at end of file From 78be2e01a7f4f224cd7075c4ac2a3837f217155e Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 7 Dec 2019 11:48:41 +0100 Subject: [PATCH 089/474] Implemented theme serialization to a file --- .gitignore | 3 +- src/main/java/envoy/client/Settings.java | 130 +++++++++--------- src/main/java/envoy/client/ui/ChatWindow.java | 1 + .../java/envoy/client/ui/SettingsScreen.java | 120 ++++------------ src/main/java/envoy/client/ui/Startup.java | 3 +- 5 files changed, 93 insertions(+), 164 deletions(-) diff --git a/.gitignore b/.gitignore index e12b13a..2b99822 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target/ -/localDB/ \ No newline at end of file +/localDB/ +/themes.ser diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index fa6088f..21a1afa 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -1,12 +1,17 @@ package envoy.client; import java.awt.Color; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; import envoy.client.ui.Theme; -import envoy.schema.User; /** * Project: envoy-client
@@ -15,19 +20,32 @@ import envoy.schema.User; * * @author Leon Hofmeister * @author Maximilian Käfer + * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha */ public class Settings { + // Actual settings accessible by the rest of the application private String username; private String email; private boolean enterToSend = true; - private Map themes = new HashMap<>(); + private Map themes; + private String currentTheme; - private String currentTheme; - // private Image profilePic; - private static Settings settings; - private Preferences prefs = Preferences.userNodeForPackage(Settings.class); + /** + * Required to save the settings. + */ + private Preferences prefs = Preferences.userNodeForPackage(Settings.class); + + /** + * User-defined themes are stored inside this file. + */ + private File themeFile = new File("themes.ser"); + + /** + * Singleton instance of this class. + */ + private static Settings settings = new Settings(); /** * The way to instantiate the settings. @@ -35,7 +53,7 @@ public class Settings { * * @since Envoy v0.2-alpha */ - private Settings() {} + private Settings() { load(); } /** * This method is used to ensure that there is only one instance of Settings. @@ -43,54 +61,44 @@ public class Settings { * @return the instance of Settings * @since Envoy v0.2-alpha */ - public static Settings getInstance() { - if (settings == null) { - settings = new Settings(); - settings.load(); + public static Settings getInstance() { return settings; } + + @SuppressWarnings("unchecked") + private void load() { + setUsername(prefs.get("username", "")); + setEmail(prefs.get("email", "")); + setEnterToSend(prefs.getBoolean("enterToSend", true)); + setCurrentTheme(prefs.get("theme", "dark")); + + // Load themes from theme file + try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) { + Object obj = in.readObject(); + if(obj instanceof HashMap) themes = (Map) obj; + } catch (IOException | ClassNotFoundException e) { + themes = new HashMap<>(); + e.printStackTrace(); } - return settings; + + // Load standard themes not defined in the themes file + themes.put("dark", + new Theme("dark", Color.black, Color.darkGray, Color.white, Color.blue, Color.white, Color.orange, Color.blue, Color.white, + Color.white)); + themes.put("light", + new Theme("light", new Color(235, 235, 235), Color.white, Color.white, Color.darkGray, Color.black, Color.orange, Color.darkGray, + Color.black, Color.black)); } - public void load() { - settings.setUsername(prefs.get("username", "")); - settings.setEmail(prefs.get("email", "")); - settings.setEnterToSend(prefs.getBoolean("enterToSend", true)); - // currentTheme = "dark"; Activate once if NullPointerException on currentTheme - // and change theme to dark or white in Settings - settings.setCurrentTheme(prefs.get("theme", "dark")); - } - - public void save() { - prefs.put("username", settings.getUsername()); - prefs.put("email", settings.getEmail()); + public void save() throws IOException{ + prefs.put("username", getUsername()); + prefs.put("email", getEmail()); prefs.put("theme", currentTheme); - System.out.println(currentTheme); - prefs.putBoolean("enterToSend", settings.isEnterToSend()); - // TODO: override themes map - - } - - public void firstSave(User user) { - - // TODO: load themes - - settings.getThemes() - .put("dark", - new Theme("dark", Color.black, Color.darkGray, Color.white, Color.blue, Color.white, Color.orange, - Color.blue, Color.white, Color.white)); - settings.getThemes() - .put("light", - new Theme("light", new Color(235, 235, 235), Color.white, Color.white, Color.darkGray, Color.black, - Color.orange, Color.darkGray, Color.black, Color.black)); - - - - - - prefs.put("username", user.getName()); - // prefs.put("email", user.getEmail()); - // prefs.putBoolean("darkMode", true); - // prefs.putBoolean("enterToSend", true); + prefs.putBoolean("enterToSend", isEnterToSend()); + + // Save themes to theme file + themeFile.createNewFile(); + try(ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) { + out.writeObject(themes); + } } public void addNewThemeToMap(Theme theme) { @@ -103,13 +111,13 @@ public class Settings { public void setCurrentTheme(String themeName) { currentTheme = themeName; } /** - * @return the username + * @return the user name * @since Envoy v0.2-alpha */ public String getUsername() { return username; } /** - * @param username the username to set + * @param username the user name to set * @since Envoy v0.2-alpha */ public void setUsername(String username) { this.username = username; } @@ -145,18 +153,4 @@ public class Settings { public Map getThemes() { return themes; } public void setThemes(Map themes) { this.themes = themes; } - - // /** - // * @return the profilePic - // * @since Envoy v0.2-alpha - // */ - // public Image getProfilePic() { return profilePic; } - // - // /** - // * @param profilePic the profilePic to set - // * @since Envoy v0.1-alpha - // */ - // public void setProfilePic(Image profilePic) { this.profilePic = profilePic; } - - -} +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index e0ea09b..d074711 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -81,6 +81,7 @@ public class ChatWindow extends JFrame { public void windowClosing(WindowEvent e) { try { localDB.saveToLocalDB(); + Settings.getInstance().save(); } catch (IOException e1) { e1.printStackTrace(); System.err.println("Could not save localDB"); diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index 80d4927..a003972 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -36,6 +36,7 @@ import envoy.client.Settings; * * @author Leon Hofmeister * @author Maximilian Käfer + * @author Kai S. K. Engelbart */ public class SettingsScreen extends JDialog { @@ -62,10 +63,10 @@ public class SettingsScreen extends JDialog { private JButton cancelButton = new JButton("Cancel"); private static int space = 5; - private boolean colorChanged = false; + private boolean colorChanged = false; + private Theme temporaryTheme; - private Theme temporaryTheme; - private static SettingsScreen settingsScreen; + private static SettingsScreen settingsScreen; // TODO: Add a JPanel with all the Information necessary: // change (Picture,Username, Email, Password) and toggle(light/dark mode, @@ -78,8 +79,6 @@ public class SettingsScreen extends JDialog { * @since Envoy v0.1-alpha */ public static void open() { - - // UIColors.getInstance(Settings.getInstance().isDarkMode()); settingsScreen = new SettingsScreen(); settingsScreen.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); settingsScreen.setModal(true); @@ -87,7 +86,7 @@ public class SettingsScreen extends JDialog { } /** - * Builds the settings screen.
+ * Builds the settings screen. * * @since Envoy v0.1-alpha */ @@ -101,9 +100,9 @@ public class SettingsScreen extends JDialog { createNewThemeButton.setEnabled(false); - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); - // ContentPane------------------------------------------------------ + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + + // Content pane GridBagLayout gbl_contentPanel = new GridBagLayout(); gbl_contentPanel.columnWidths = new int[] { 1, 1 }; @@ -155,7 +154,7 @@ public class SettingsScreen extends JDialog { contentPanel.add(options, gbc_optionsList); - // ThemeContent --- + // Theme content gbc_themeContent = new GridBagConstraints(); gbc_themeContent.fill = GridBagConstraints.BOTH; @@ -166,8 +165,6 @@ public class SettingsScreen extends JDialog { GridBagLayout gbl_themeLayout = new GridBagLayout(); - // themeContent.setSelectionForeground(theme.getUserNameColor()); - // themeContent.setSelectionBackground(theme.getSelectionColor()); themeContent.setForeground(theme.getUserNameColor()); themeContent.setBackground(theme.getCellColor()); @@ -181,7 +178,6 @@ public class SettingsScreen extends JDialog { themes.setBackground(theme.getUserNameColor()); themes.setForeground(theme.getBackgroundColor()); themes.setSelectedItem(Settings.getInstance().getCurrentTheme()); - // themes.setBorder(null); themes.addItemListener(new ItemListener() { @@ -191,7 +187,6 @@ public class SettingsScreen extends JDialog { System.out.println(selectedValue); selectedTheme = Settings.getInstance().getThemes().get(selectedValue); } - }); GridBagConstraints gbc_themes = new GridBagConstraints(); @@ -206,24 +201,9 @@ public class SettingsScreen extends JDialog { colorsPanel.setLayout((LayoutManager) new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getBackgroundColor(), "Background", 1); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getCellColor(), "Cells", 2); buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getBackgroundColor(), - "Background", - 1); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getCellColor(), - "Cells", - 2); - buildCustomizeElement(new JPanel(), - new JButton(), new JTextPane(), theme, @@ -231,53 +211,17 @@ public class SettingsScreen extends JDialog { "Interactable Foreground", 3); buildCustomizeElement(new JPanel(), - new JButton(), new JTextPane(), theme, theme.getInteractableBackgroundColor(), "Interactable Background", 4); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getMessageColorChat(), - "Messages Chat", - 5); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getDateColorChat(), - "Date Chat", - 6); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getSelectionColor(), - "Selection", - 7); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getTypingMessageColor(), - "Typing Message", - 8); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getUserNameColor(), - "User Names", - 9); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getMessageColorChat(), "Messages Chat", 5); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getDateColorChat(), "Date Chat", 6); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getSelectionColor(), "Selection", 7); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getTypingMessageColor(), "Typing Message", 8); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getUserNameColor(), "User Names", 9); GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; @@ -298,16 +242,14 @@ public class SettingsScreen extends JDialog { String s = JOptionPane.showInputDialog("Enter a name for the new theme"); System.out.println(s); Settings.getInstance() - .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), - temporaryTheme.getCellColor(), temporaryTheme.getInteractableForegroundColor(), - temporaryTheme.getInteractableBackgroundColor(), temporaryTheme.getMessageColorChat(), - temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), + .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(), + temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(), + temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor())); themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName(); - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); createNewThemeButton.setEnabled(false); themes.addItem(themeArray[themeArray.length - 1]); @@ -421,27 +363,18 @@ public class SettingsScreen extends JDialog { } - public void updateColorVariables(String key) { + private void updateColorVariables(String key) { Theme theme = Settings.getInstance().getThemes().get(key); temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getInteractableForegroundColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getInteractableBackgroundColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableForegroundColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getSelectionColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getTypingMessageColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getTypingMessageColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); colorsPanel.removeAll(); @@ -526,10 +459,9 @@ public class SettingsScreen extends JDialog { colorsPanel.add(createNewThemeButton, gbc_createNewTheme); } - public void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); } + private void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); } - public void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, - String name, int yIndex) { + private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, String name, int yIndex) { textPane.setFont(new Font("Arial", Font.PLAIN, 14)); textPane.setBackground(theme.getBackgroundColor()); textPane.setForeground(theme.getUserNameColor()); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 2781a8a..f940191 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -21,6 +21,7 @@ import envoy.exception.EnvoyException; * * @author Leon Hofmeister * @author Maximilian Käfer + * @author Kai S. K. Engelbart * @since Envoy v0.1-alpha */ public class Startup { @@ -61,7 +62,7 @@ public class Startup { "Local DB error", JOptionPane.WARNING_MESSAGE); } - Settings.getInstance().firstSave(client.getSender()); + Settings.getInstance().setUsername(userName); EventQueue.invokeLater(() -> { try { From 6f7bee4509ae7b05805705cd5bc9402b888a58de Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 7 Dec 2019 13:02:38 +0100 Subject: [PATCH 090/474] Added new Envoy logo designed by @DieGurke --- src/main/java/envoy/client/ui/ChatWindow.java | 4 +++- src/main/resources/envoy_logo.png | Bin 8152 -> 30553 bytes src/main/resources/envoy_logo_alpha.png | Bin 0 -> 28525 bytes src/main/resources/envoy_logo_old.png | Bin 0 -> 8152 bytes 4 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/envoy_logo_alpha.png create mode 100644 src/main/resources/envoy_logo_old.png diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index b43bb65..05da3c3 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -6,6 +6,7 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; +import java.awt.Toolkit; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; @@ -59,7 +60,7 @@ public class ChatWindow extends JFrame { private Chat currentChat; private JTextArea messageEnterTextArea; - + private static final Logger logger = Logger.getLogger(ChatWindow.class.getSimpleName()); public ChatWindow(Client client, LocalDB localDB) { @@ -70,6 +71,7 @@ public class ChatWindow extends JFrame { setBounds(100, 100, 600, 800); setTitle("Envoy"); setLocationRelativeTo(null); + setIconImage(Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); // Save chats when window closes addWindowListener(new WindowAdapter() { diff --git a/src/main/resources/envoy_logo.png b/src/main/resources/envoy_logo.png index 35ef7d9fd78cc3b79454de104ae59fbb65c0b050..1606bd58e0c3a75a3f85b439c283922293bb6f05 100644 GIT binary patch literal 30553 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 ZCHeJUhpIFDU%4v|?Kj$&vB&Q6{{p0b=l1{r literal 8152 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 NRM)?ddk+53e*k9UjZ6Rl literal 0 HcmV?d00001 diff --git a/src/main/resources/envoy_logo_old.png b/src/main/resources/envoy_logo_old.png new file mode 100644 index 0000000000000000000000000000000000000000..35ef7d9fd78cc3b79454de104ae59fbb65c0b050 GIT binary patch literal 8152 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 Date: Sat, 7 Dec 2019 13:25:39 +0100 Subject: [PATCH 091/474] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..9d4ae77 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at kske@outlook.de. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq From 233e3bcb83e791fd752ad79b260c97dc7ce3fd38 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 7 Dec 2019 13:31:08 +0100 Subject: [PATCH 092/474] Fixes themes list display bug and error when loading client with custom theme --- src/main/java/envoy/client/Settings.java | 1 + src/main/java/envoy/client/ui/SettingsScreen.java | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 21a1afa..e84e647 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -76,6 +76,7 @@ public class Settings { if(obj instanceof HashMap) themes = (Map) obj; } catch (IOException | ClassNotFoundException e) { themes = new HashMap<>(); + currentTheme = "dark"; e.printStackTrace(); } diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index a003972..6d5c94d 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -8,7 +8,6 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; -import java.awt.LayoutManager; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Arrays; @@ -48,8 +47,7 @@ public class SettingsScreen extends JDialog { private JPanel buttonPane = new JPanel(); private JPanel themeContent = new JPanel(); - private String[] themeArray = { Settings.getInstance().getThemes().get("dark").getThemeName(), - Settings.getInstance().getThemes().get("light").getThemeName() }; + private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]); private JComboBox themes = new JComboBox(themeArray); private GridBagConstraints gbc_themeContent = new GridBagConstraints(); @@ -198,10 +196,16 @@ public class SettingsScreen extends JDialog { themeContent.add(themes, gbc_themes); - colorsPanel.setLayout((LayoutManager) new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); + colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getBackgroundColor(), "Background", 1); + buildCustomizeElement(new JPanel(), + new JButton(), + new JTextPane(), + theme, + theme.getBackgroundColor(), + "Background", + 1); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getCellColor(), "Cells", 2); buildCustomizeElement(new JPanel(), new JButton(), From 0fb8af47d653fd8a03b309f7e2ebde763eda34b4 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 7 Dec 2019 13:33:55 +0100 Subject: [PATCH 093/474] Create issue templates Now issues can be easily created using these templates --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..2b978b3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: CyB3RC0nN0R, delvh, DieGurke, derharry333 + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..fbdebf6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: CyB3RC0nN0R, delvh, DieGurke + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From c078c33d8b1a15bccc9cdb6b093b0509e7c4986b Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 7 Dec 2019 14:54:03 +0100 Subject: [PATCH 094/474] Fixed an indentation error in Javadoc --- src/main/java/envoy/client/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 8cea817..8923cd8 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -114,7 +114,7 @@ public class Config { /** * Changes the default local database. * Exclusively intended for development purposes. - * + * * @param localDB the file containing the local database * @since Envoy v0.1-alpha **/ From bafadca4cbd4fca71145556ae9981bb8e97acab6 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 7 Dec 2019 17:58:59 +0100 Subject: [PATCH 095/474] Revised requested changes besides 2 (please change by yourself) --- src/main/java/envoy/client/Config.java | 2 - src/main/java/envoy/client/Settings.java | 32 +++++++ src/main/java/envoy/client/ui/ChatWindow.java | 21 ++-- .../java/envoy/client/ui/SettingsScreen.java | 95 ++++++++++++++----- src/main/java/envoy/client/ui/Theme.java | 64 ++++++++++++- .../envoy/client/ui/UserListRenderer.java | 1 - 6 files changed, 180 insertions(+), 35 deletions(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 8923cd8..bbd3b72 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -121,14 +121,12 @@ public class Config { public void setLocalDB(File localDB) { this.localDB = localDB; } /** - * * @return the current time (milliseconds) that is waited between Syncs * @since Envoy v0.1-alpha */ public int getSyncTimeout() { return syncTimeout; } /** - * * @param syncTimeout sets the time (milliseconds) during which Sync waits * @since Envoy v0.1-alpha */ diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index e84e647..91f696f 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -89,6 +89,12 @@ public class Settings { Color.black, Color.black)); } + /** + * updates prefs when save button is clicked + * + * @throws IOException + * @since Envoy v0.2-alpha + */ public void save() throws IOException{ prefs.put("username", getUsername()); prefs.put("email", getEmail()); @@ -102,13 +108,29 @@ public class Settings { } } + /** + * adds new theme to the theme map and sets current theme to the new theme. + * + * @param theme + * @since Envoy v0.2-alpha + */ public void addNewThemeToMap(Theme theme) { settings.getThemes().put(theme.getThemeName(), theme); currentTheme = theme.getThemeName(); } + /** + * @return {@link currentTheme} + * @since Envoy v0.2-alpha + */ public String getCurrentTheme() { return currentTheme; } + /** + * Sets the currentTheme + * + * @param themeName + * @since Envoy v0.2-alpha + */ public void setCurrentTheme(String themeName) { currentTheme = themeName; } /** @@ -151,7 +173,17 @@ public class Settings { */ public void setEnterToSend(boolean enterToSend) { this.enterToSend = enterToSend; } + /** + * @return {@link themes} map + * @since Envoy v0.2-alpha + */ public Map getThemes() { return themes; } + /** + * Sets {@link themes} + * + * @param themes + * @since Envoy v0.2-alpha + */ public void setThemes(Map themes) { this.themes = themes; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index fccbe06..6867f5e 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,6 +1,5 @@ package envoy.client.ui; -import java.awt.Color; import java.awt.ComponentOrientation; import java.awt.Font; import java.awt.GridBagConstraints; @@ -136,6 +135,7 @@ public class ChatWindow extends JFrame { && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); + } } }); // Checks for changed Message @@ -244,6 +244,7 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); } + /** * Used to immediately reload the ChatWindow when settings were changed. @@ -282,19 +283,22 @@ public class ChatWindow extends JFrame { userList.setSelectionBackground(theme.getSelectionColor()); userList.setForeground(theme.getUserNameColor()); userList.setBackground(theme.getCellColor()); - } - + private void postMessage(JList messageList) { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(this, + "Please select a recipient!", + "Cannot send message", + JOptionPane.INFORMATION_MESSAGE); return; } if (!messageEnterTextArea.getText().isEmpty()) try { // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient()); + final Message message = localDB.createMessage(messageEnterTextArea.getText(), + currentChat.getRecipient().getID()); currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); @@ -344,7 +348,8 @@ public class ChatWindow extends JFrame { new Thread(() -> { // Synchronize - localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + localDB.applySync( + client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); // Process unread messages localDB.addUnreadMessagesToLocalDB(); @@ -354,7 +359,8 @@ public class ChatWindow extends JFrame { readCurrentChat(); // Update UI - SwingUtilities.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); + SwingUtilities + .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); }).start(); }).start(); } @@ -371,3 +377,4 @@ public class ChatWindow extends JFrame { */ private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } } + diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index d2b2db3..bd80c2e 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -11,6 +11,7 @@ import java.awt.Insets; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Arrays; +import java.util.logging.Logger; import javax.swing.BoxLayout; import javax.swing.DefaultListModel; @@ -24,6 +25,7 @@ import javax.swing.JPanel; import javax.swing.JTextPane; import javax.swing.ListSelectionModel; +import envoy.client.LocalDB; import envoy.client.Settings; /** @@ -64,6 +66,8 @@ public class SettingsScreen extends JDialog { private boolean colorChanged = false; private Theme temporaryTheme; + private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); + private static SettingsScreen settingsScreen; // TODO: Add a JPanel with all the Information necessary: @@ -89,8 +93,7 @@ public class SettingsScreen extends JDialog { * @since Envoy v0.1-alpha */ private SettingsScreen() { - - System.out.println(Settings.getInstance().getCurrentTheme()); + logger.info(Settings.getInstance().getCurrentTheme()); setBounds(10, 10, 450, 650); getContentPane().setLayout(new BorderLayout()); @@ -98,7 +101,8 @@ public class SettingsScreen extends JDialog { createNewThemeButton.setEnabled(false); - temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); // Content pane GridBagLayout gbl_contentPanel = new GridBagLayout(); @@ -147,13 +151,10 @@ public class SettingsScreen extends JDialog { gbc_optionsList.insets = new Insets(space, space, space, space); optionsListModel.addElement("Color Themes"); - options.setModel(optionsListModel); - contentPanel.add(options, gbc_optionsList); // Theme content - gbc_themeContent = new GridBagConstraints(); gbc_themeContent.fill = GridBagConstraints.BOTH; gbc_themeContent.gridx = 1; @@ -206,7 +207,13 @@ public class SettingsScreen extends JDialog { theme.getBackgroundColor(), "Background", 1); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getCellColor(), "Cells", 2); + buildCustomizeElement(new JPanel(), + new JButton(), + new JTextPane(), + theme, + theme.getCellColor(), + "Cells", + 2); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), @@ -221,11 +228,41 @@ public class SettingsScreen extends JDialog { theme.getInteractableBackgroundColor(), "Interactable Background", 4); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getMessageColorChat(), "Messages Chat", 5); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getDateColorChat(), "Date Chat", 6); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getSelectionColor(), "Selection", 7); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getTypingMessageColor(), "Typing Message", 8); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getUserNameColor(), "User Names", 9); + buildCustomizeElement(new JPanel(), + new JButton(), + new JTextPane(), + theme, + theme.getMessageColorChat(), + "Messages Chat", + 5); + buildCustomizeElement(new JPanel(), + new JButton(), + new JTextPane(), + theme, + theme.getDateColorChat(), + "Date Chat", + 6); + buildCustomizeElement(new JPanel(), + new JButton(), + new JTextPane(), + theme, + theme.getSelectionColor(), + "Selection", + 7); + buildCustomizeElement(new JPanel(), + new JButton(), + new JTextPane(), + theme, + theme.getTypingMessageColor(), + "Typing Message", + 8); + buildCustomizeElement(new JPanel(), + new JButton(), + new JTextPane(), + theme, + theme.getUserNameColor(), + "User Names", + 9); GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; @@ -246,14 +283,16 @@ public class SettingsScreen extends JDialog { String s = JOptionPane.showInputDialog("Enter a name for the new theme"); System.out.println(s); Settings.getInstance() - .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(), - temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(), - temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), + .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), + temporaryTheme.getCellColor(), temporaryTheme.getInteractableForegroundColor(), + temporaryTheme.getInteractableBackgroundColor(), temporaryTheme.getMessageColorChat(), + temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor())); themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName(); - temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); createNewThemeButton.setEnabled(false); themes.addItem(themeArray[themeArray.length - 1]); @@ -264,7 +303,7 @@ public class SettingsScreen extends JDialog { // TODO: Create new Theme } catch (Exception e) { - System.err.println("New theme couldn't be created! " + e); + logger.info("New theme couldn't be created! " + e); e.printStackTrace(); } }); @@ -326,7 +365,7 @@ public class SettingsScreen extends JDialog { revalidate(); repaint(); } catch (Exception e) { - System.err.println("Something went wrong when changing the setting"); + logger.info("Something went wrong when changing the setting"); settingsScreen.dispose(); } }); @@ -373,12 +412,21 @@ public class SettingsScreen extends JDialog { temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableForegroundColor(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor(), + Settings.getInstance() + .getThemes() + .get(Settings.getInstance().getCurrentTheme()) + .getInteractableForegroundColor(), + Settings.getInstance() + .getThemes() + .get(Settings.getInstance().getCurrentTheme()) + .getInteractableBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getSelectionColor(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getTypingMessageColor(), + Settings.getInstance() + .getThemes() + .get(Settings.getInstance().getCurrentTheme()) + .getTypingMessageColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); colorsPanel.removeAll(); @@ -465,7 +513,8 @@ public class SettingsScreen extends JDialog { private void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); } - private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, String name, int yIndex) { + private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, + String name, int yIndex) { textPane.setFont(new Font("Arial", Font.PLAIN, 14)); textPane.setBackground(theme.getBackgroundColor()); textPane.setForeground(theme.getUserNameColor()); @@ -497,7 +546,7 @@ public class SettingsScreen extends JDialog { } } catch (Exception e) { - System.err.println("An error occured while opening Color Chooser: " + e); + logger.info("An error occured while opening Color Chooser: " + e); e.printStackTrace(); } }); diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index ad8430b..a0ef259 100644 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -4,7 +4,6 @@ import java.awt.Color; import java.io.Serializable; /** - * * Project: envoy-client
* File: Theme.java
* Created: 23 Nov 2019
@@ -50,26 +49,70 @@ public class Theme implements Serializable { other.typingMessageColor, other.userNameColor); } + /** + * @return name of the theme + * @since Envoy v0.2-alpha + */ public String getThemeName() { return themeName; } + /** + * @return interactableForegroundColor + * @since Envoy v0.2-alpha + */ public Color getInteractableForegroundColor() { return interactableForegroundColor; } + /** + * @return messageColorChat + * @since Envoy v0.2-alpha + */ public Color getMessageColorChat() { return messageColorChat; } + /** + * @return dateColorChat + * @since Envoy v0.2-alpha + */ public Color getDateColorChat() { return dateColorChat; } + /** + * @return selectionColor + * @since Envoy v0.2-alpha + */ public Color getSelectionColor() { return selectionColor; } + /** + * @return typingMessageColor + * @since Envoy v0.2-alpha + */ public Color getTypingMessageColor() { return typingMessageColor; } + /** + * @return backgroundColor + * @since Envoy v0.2-alpha + */ public Color getBackgroundColor() { return backgroundColor; } + /** + * @return cellColor + * @since Envoy v0.2-alpha + */ public Color getCellColor() { return cellColor; } + /** + * @return interactableBackgroundColor + * @since Envoy v0.2-alpha + */ public Color getInteractableBackgroundColor() { return interactableBackgroundColor; } + /** + * @return userNameColor + * @since Envoy v0.2-alpha + */ public Color getUserNameColor() { return userNameColor; } + /** + * @return a color array containing all colors of this theme + * @since Envoy v0.2-alpha + */ public Color[] getAllColors() { Color[] c = new Color[9]; c[0] = backgroundColor; @@ -85,6 +128,24 @@ public class Theme implements Serializable { return c; } + /** + * Sets the a specific {@link Color} in this theme to a new {@link Color} + * + * @param index - index of the color
+ * 0 = backgroundColor
+ * 1 = cellColor
+ * 2 = interactableForegroundColor
+ * 3 = interactableBackgroundColor
+ * 4 = messageColorChat
+ * 5 = dateColorChat
+ * 6 = selectionColor
+ * 7 = typingMessageColor
+ * 8 = userNameColor
+ *
+ * + * @param newColor - new {@link Color} to be set + * @since Envoy 0.2-alpha + */ public void setColor(int index, Color newColor) { switch (index) { case 0: @@ -114,7 +175,6 @@ public class Theme implements Serializable { case 8: this.userNameColor = newColor; break; - } } diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index 3258afa..c730e74 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -45,7 +45,6 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { // Getting the UserNameColor of the current theme String textColor = null; - textColor = toHex( Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); switch (status) { From 10b1cc0001e66cd1d2afe08ea6f6ad347b2d2206 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 7 Dec 2019 21:14:55 +0100 Subject: [PATCH 096/474] Silent failure when StatusTrayIcon is not supported on a platform --- src/main/java/envoy/client/ui/Startup.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 25af819..edd5aa2 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -71,12 +71,17 @@ public class Startup { JOptionPane.WARNING_MESSAGE); } Settings.getInstance().setUsername(userName); - + EventQueue.invokeLater(() -> { try { ChatWindow chatWindow = new ChatWindow(client, localDB); - new StatusTrayIcon(chatWindow).show(); chatWindow.setVisible(true); + + try { + new StatusTrayIcon(chatWindow).show(); + } catch (EnvoyException e) { + logger.warning("The StatusTrayIcon is not supported on this platform!"); + } } catch (Exception e) { e.printStackTrace(); } From 4d7e0bdbe0ca045f5265b88a824fc7b67cb5d893 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 7 Dec 2019 22:48:12 +0100 Subject: [PATCH 097/474] Primary Button Took primaryButton class from corresponding branch. Implemented constructors in ChatWindow. --- src/main/java/envoy/client/ui/ChatWindow.java | 9 ++- .../java/envoy/client/ui/PrimaryButton.java | 61 +++++++++++++++++++ 2 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 src/main/java/envoy/client/ui/PrimaryButton.java diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 6867f5e..7b38a3e 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -15,7 +15,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.DefaultListModel; -import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JOptionPane; @@ -63,8 +62,8 @@ public class ChatWindow extends JFrame { private JScrollPane scrollPane = new JScrollPane(); private JTextPane textPane = new JTextPane(); // private JCheckBox jCbChangeMode; - private JButton postButton = new JButton("Post"); - private JButton settingsButton = new JButton("Settings"); + private PrimaryButton postButton; + private PrimaryButton settingsButton; private static int space = 4; @@ -155,7 +154,7 @@ public class ChatWindow extends JFrame { contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); // Post Button - postButton.setBorderPainted(false); + postButton = new PrimaryButton("Post"); GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; @@ -168,7 +167,7 @@ public class ChatWindow extends JFrame { contentPane.add(postButton, gbc_moveSelectionPostButton); // Settings Button - settingsButton.setBorderPainted(false); + settingsButton = new PrimaryButton("Settings"); GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); diff --git a/src/main/java/envoy/client/ui/PrimaryButton.java b/src/main/java/envoy/client/ui/PrimaryButton.java new file mode 100644 index 0000000..06df82f --- /dev/null +++ b/src/main/java/envoy/client/ui/PrimaryButton.java @@ -0,0 +1,61 @@ +package envoy.client.ui; + +import java.awt.Graphics; + +import javax.swing.JButton; + +/** + * Project: envoy-clientChess
+ * File: PrimaryButton.javaEvent.java
+ * Created: 07.12.2019
+ * + * @author Kai S. K. Engelbart + */ +public class PrimaryButton extends JButton { + + private static final long serialVersionUID = 3662266120667728364L; + + private int arcSize; + + /** + * Creates a primary button with a white text color and a purple background + * color. + * + * @param title the title of the button + */ + public PrimaryButton(String title) { this(title, 6); } + + /** + * Creates a primary button with a white text color and a purple background + * color. + * + * @param title the title of the button + * @param the size of the arc used to draw the round button edges + */ + public PrimaryButton(String title, int arcSize) { + super(title); + // setForeground(new Color(255, 255, 255)); + // setBackground(new Color(102, 51, 153)); + setBorderPainted(false); + setFocusPainted(false); + setContentAreaFilled(false); + this.arcSize = arcSize; + } + + @Override + protected void paintComponent(Graphics g) { + g.setColor(getBackground()); + g.fillRoundRect(0, 0, getWidth(), getHeight(), arcSize, arcSize); + super.paintComponent(g); + } + + /** + * @return the arcSize + */ + public int getArcSize() { return arcSize; } + + /** + * @param arcSize the arcSize to set + */ + public void setArcSize(int arcSize) { this.arcSize = arcSize; } +} \ No newline at end of file From 3c8a4c445f4b1f8b652a634e7dc0f7e609825a9a Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 7 Dec 2019 23:23:25 +0100 Subject: [PATCH 098/474] Primary TextArea * Added PrimaryTextArea Class * Implemented PrimaryTextArea in ChatWindow (messageEnterArea) * Made some slight adjustments to the PrimaryButton Class --- src/main/java/envoy/client/ui/ChatWindow.java | 13 ++-- .../java/envoy/client/ui/PrimaryButton.java | 13 ++-- .../java/envoy/client/ui/PrimaryTextArea.java | 67 +++++++++++++++++++ 3 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 src/main/java/envoy/client/ui/PrimaryTextArea.java diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 7b38a3e..14065b0 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -20,7 +20,6 @@ import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; -import javax.swing.JTextArea; import javax.swing.JTextPane; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; @@ -55,7 +54,7 @@ public class ChatWindow extends JFrame { private LocalDB localDB; // GUI components private JPanel contentPane = new JPanel(); - private JTextArea messageEnterTextArea = new JTextArea(); + private PrimaryTextArea messageEnterTextArea; private JList userList = new JList<>(); private Chat currentChat; private JList messageList = new JList<>(); @@ -125,6 +124,9 @@ public class ChatWindow extends JFrame { gbc_scrollPane.insets = new Insets(space, space, space, space); contentPane.add(scrollPane, gbc_scrollPane); + // Checks for changed Message + messageEnterTextArea = new PrimaryTextArea(space); + // Message enter field messageEnterTextArea.addKeyListener(new KeyAdapter() { @@ -137,12 +139,7 @@ public class ChatWindow extends JFrame { } } }); - // Checks for changed Message - messageEnterTextArea.setWrapStyleWord(true); - messageEnterTextArea.setLineWrap(true); - messageEnterTextArea.setBorder(null); - messageEnterTextArea.setFont(new Font("Arial", Font.PLAIN, 17)); - messageEnterTextArea.setBorder(new EmptyBorder(space, space, space, space)); + GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; diff --git a/src/main/java/envoy/client/ui/PrimaryButton.java b/src/main/java/envoy/client/ui/PrimaryButton.java index 06df82f..2e528db 100644 --- a/src/main/java/envoy/client/ui/PrimaryButton.java +++ b/src/main/java/envoy/client/ui/PrimaryButton.java @@ -5,11 +5,12 @@ import java.awt.Graphics; import javax.swing.JButton; /** - * Project: envoy-clientChess
+ * Project: envoy-client
* File: PrimaryButton.javaEvent.java
* Created: 07.12.2019
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer */ public class PrimaryButton extends JButton { @@ -18,19 +19,19 @@ public class PrimaryButton extends JButton { private int arcSize; /** - * Creates a primary button with a white text color and a purple background - * color. + * Creates a primary button * * @param title the title of the button + * @since Envoy 0.2-alpha */ public PrimaryButton(String title) { this(title, 6); } /** - * Creates a primary button with a white text color and a purple background - * color. + * Creates a primary button * * @param title the title of the button * @param the size of the arc used to draw the round button edges + * @since Envoy 0.2-alpha */ public PrimaryButton(String title, int arcSize) { super(title); @@ -51,11 +52,13 @@ public class PrimaryButton extends JButton { /** * @return the arcSize + * @since Envoy 0.2-alpha */ public int getArcSize() { return arcSize; } /** * @param arcSize the arcSize to set + * @since Envoy 0.2-alpha */ public void setArcSize(int arcSize) { this.arcSize = arcSize; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/PrimaryTextArea.java b/src/main/java/envoy/client/ui/PrimaryTextArea.java new file mode 100644 index 0000000..3f350ed --- /dev/null +++ b/src/main/java/envoy/client/ui/PrimaryTextArea.java @@ -0,0 +1,67 @@ +package envoy.client.ui; + +import java.awt.Font; +import java.awt.Graphics; + +import javax.swing.JTextArea; +import javax.swing.border.EmptyBorder; + +/** + * Project: envoy-client
+ * File: PrimaryTextArea.javaEvent.java
+ * Created: 07.12.2019
+ * + * @author Maximilian Käfer + */ +public class PrimaryTextArea extends JTextArea { + + private static final long serialVersionUID = 1L; + + private int arcSize; + + /** + * Creates TextArea + * + * @param borderSpace + * @since Envoy 0.2-alpha + */ + public PrimaryTextArea(int borderSpace) { this(6, borderSpace); } + + /** + * Creates TextArea + * + * @param arcSize + * @param borderSpace + * @since Envoy 0.2-alpha + */ + public PrimaryTextArea(int arcSize, int borderSpace) { + super(); + setWrapStyleWord(true); + setLineWrap(true); + setBorder(null); + setFont(new Font("Arial", Font.PLAIN, 17)); + setBorder(new EmptyBorder(borderSpace, borderSpace, borderSpace, borderSpace)); + setOpaque(false); + + this.arcSize = arcSize; + } + + @Override + protected void paintComponent(Graphics g) { + g.setColor(getBackground()); + g.fillRoundRect(0, 0, getWidth(), getHeight(), arcSize, arcSize); + super.paintComponent(g); + } + + /** + * @return the arcSize + * @since Envoy 0.2-alpha + */ + public int getArcSize() { return arcSize; } + + /** + * @param arcSize the arcSize to set + * @since Envoy 0.2-alpha + */ + public void setArcSize(int arcSize) { this.arcSize = arcSize; } +} From 117f9043cedb7f334824533c7b5f4202424e667c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 11 Dec 2019 18:52:30 +0100 Subject: [PATCH 099/474] Added offline mode to Client + Saving the user ID in Settings + Loading the user ID from Settings in Client if the server can't be reached --- src/main/java/envoy/client/Client.java | 63 ++++++++++++---------- src/main/java/envoy/client/Settings.java | 25 ++++++--- src/main/java/envoy/client/ui/Startup.java | 21 ++++++-- 3 files changed, 73 insertions(+), 36 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 8f96739..a6a7f36 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -10,6 +10,7 @@ import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; +import envoy.exception.EnvoyException; import envoy.schema.ObjectFactory; import envoy.schema.Sync; import envoy.schema.User; @@ -29,14 +30,18 @@ public class Client { private ObjectFactory objectFactory = new ObjectFactory(); private Config config; private User sender, recipient; + private boolean online = false; private static final Logger logger = Logger.getLogger(Client.class.getSimpleName()); - public Client(Config config, String username) { + public Client(Config config, String userName) throws EnvoyException { this.config = config; - sender = getUser(username); - - logger.info("ID: " + sender.getID()); + sender = getUser(userName); + + // Update the user ID in the cache + Settings.getInstance().setUserID(sender.getID()); + + logger.info("Client user ID: " + sender.getID()); } private R post(String uri, T body, Class responseBodyClass) { @@ -48,7 +53,6 @@ public class Client { client.close(); return responseBody; - } /** @@ -63,9 +67,7 @@ public class Client { user.setID(-1); sendSync.getUsers().add(user); - Sync returnSendSync = post( - String - .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + Sync returnSendSync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), sendSync, Sync.class); return returnSendSync; @@ -77,29 +79,33 @@ public class Client { * * @param name - the name of the {@link User} * @return a {@link User} with the specified name + * @throws EnvoyException if the server does not return the requested ID * @since Envoy v0.1-alpha */ - private User getUser(String name) { + private User getUser(String name) throws EnvoyException { + // Create a sync with only a user with the requested name Sync senderSync = objectFactory.createSync(); User user = objectFactory.createUser(); user.setName(name); senderSync.getUsers().add(user); - Sync returnSenderSync = post( - String - .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), - senderSync, - Sync.class); + try { + Sync sync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + senderSync, + Sync.class); - User returnSender = objectFactory.createUser(); - - if (returnSenderSync.getUsers().size() == 1) { - returnSender = returnSenderSync.getUsers().get(0); - } else { - logger.warning("ERROR exiting..."); + // Expecting a single user with an ID + if (sync.getUsers().size() == 1) { + online = true; + return sync.getUsers().get(0); + } else throw new EnvoyException("Unexpected response from Envoy Server"); + } catch (Exception e) { + logger.warning("Could not connect to server, trying offline mode."); + if (Settings.getInstance().getUserID() != -1) { + user.setID(Settings.getInstance().getUserID()); + return user; + } else throw new EnvoyException("Could not enter offline mode."); } - - return returnSender; } /** @@ -134,7 +140,8 @@ public class Client { * their updated UserStatus to the client.)
* * @param userId the id of the {@link Client} who sends the {@link Sync} - * @param sync the sync object (yet to be converted from java class to sync.xml) + * @param sync the sync object (yet to be converted from java class to + * sync.xml) * @return a returnSync.xml file * @since Envoy v0.1-alpha */ @@ -151,10 +158,7 @@ public class Client { } // Send sync - return post(String - .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), - sync, - Sync.class); + return post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), sync, Sync.class); } /** @@ -182,4 +186,9 @@ public class Client { * @since Envoy v0.1-alpha */ public boolean hasRecipient() { return recipient != null; } + + /** + * @return {@code true} if a connection to the server could be established + */ + public boolean isOnline() { return online; } } diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 91f696f..851c936 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -27,6 +27,7 @@ public class Settings { // Actual settings accessible by the rest of the application private String username; + private long userID; private String email; private boolean enterToSend = true; private Map themes; @@ -66,6 +67,7 @@ public class Settings { @SuppressWarnings("unchecked") private void load() { setUsername(prefs.get("username", "")); + setUserID(prefs.getLong("userID", -1)); setEmail(prefs.get("email", "")); setEnterToSend(prefs.getBoolean("enterToSend", true)); setCurrentTheme(prefs.get("theme", "dark")); @@ -73,9 +75,9 @@ public class Settings { // Load themes from theme file try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) { Object obj = in.readObject(); - if(obj instanceof HashMap) themes = (Map) obj; + if (obj instanceof HashMap) themes = (Map) obj; } catch (IOException | ClassNotFoundException e) { - themes = new HashMap<>(); + themes = new HashMap<>(); currentTheme = "dark"; e.printStackTrace(); } @@ -90,20 +92,21 @@ public class Settings { } /** - * updates prefs when save button is clicked + * Updates the preferences when the save button is clicked. * * @throws IOException * @since Envoy v0.2-alpha */ - public void save() throws IOException{ + public void save() throws IOException { prefs.put("username", getUsername()); + prefs.putLong("userID", getUserID()); prefs.put("email", getEmail()); prefs.put("theme", currentTheme); prefs.putBoolean("enterToSend", isEnterToSend()); - + // Save themes to theme file themeFile.createNewFile(); - try(ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) { + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) { out.writeObject(themes); } } @@ -145,6 +148,16 @@ public class Settings { */ public void setUsername(String username) { this.username = username; } + /** + * @return the userID + */ + public long getUserID() { return userID; } + + /** + * @param userID the userID to set + */ + public void setUserID(long userID) { this.userID = userID; } + /** * @return the email associated with that user. * @since Envoy v0.2-alpha diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index edd5aa2..c8373ed 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -16,7 +16,7 @@ import envoy.exception.EnvoyException; /** * Starts the Envoy client and prompts the user to enter their name. - * + *
* Project: envoy-client
* File: Startup.java
* Created: 12 Oct 2019
@@ -48,19 +48,34 @@ public class Startup { // Override configuration values with command line arguments if (args.length > 0) config.load(args); + // Check if all configuration values have been initialized if (!config.isInitialized()) { logger.severe("Server or port are not defined. Exiting..."); JOptionPane.showMessageDialog(null, "Error loading configuration values.", "Configuration error", JOptionPane.ERROR_MESSAGE); System.exit(1); } + // Ask the user for their user name String userName = JOptionPane.showInputDialog("Please enter your username"); if (userName == null || userName.isEmpty()) { logger.severe("User name is not set or empty. Exiting..."); System.exit(1); } - Client client = new Client(config, userName); - LocalDB localDB = new LocalDB(client.getSender()); + + // Acquire the client user (with ID) either from the server or from the local + // cache (Preferences), which triggers offline mode + Client client; + try { + client = new Client(config, userName); + } catch (Exception e1) { + logger.log(Level.SEVERE, "Failed to acquire client user ID", e1); + JOptionPane.showMessageDialog(null, e1.toString(), "Client error", JOptionPane.ERROR_MESSAGE); + System.exit(1); + return; + } + + // Load the local database + LocalDB localDB = new LocalDB(client.getSender()); try { localDB.initializeDBFile(config.getLocalDB()); } catch (EnvoyException e) { From daca66d729c8f0b12e49d7d5f27d2163527bdb74 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Fri, 13 Dec 2019 08:50:15 +0100 Subject: [PATCH 100/474] Moved client.properties loading from Startup to Config --- src/main/java/envoy/client/Config.java | 38 ++++++++++++++-------- src/main/java/envoy/client/ui/Startup.java | 25 +++++--------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index bbd3b72..0c3a000 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -3,6 +3,8 @@ package envoy.client; import java.io.File; import java.util.Properties; +import envoy.exception.EnvoyException; + /** * Project: envoy-client
* File: Config.java
@@ -29,17 +31,26 @@ public class Config { /** * Defaults to the {@code client.properties} file for information. + * This file contains information about + * the server and port, as well as the path to the local + * database and the synchronization timeout * - * @param properties a {@link Properties} object containing information about - * the server and port, as well as the path to the local - * database and the synchronization timeout + * @throws EnvoyException if the {@code client.properties} file could not be + * loaded * @since Envoy v0.1-alpha */ - public void load(Properties properties) { - if (properties.containsKey("server")) server = properties.getProperty("server"); - if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); - localDB = new File(properties.getProperty("localDB", ".\\localDB")); - syncTimeout = Integer.parseInt(properties.getProperty("syncTimeout", "1000")); + public void load() throws EnvoyException { + ClassLoader loader = getClass().getClassLoader(); + try { + Properties properties = new Properties(); + properties.load(loader.getResourceAsStream("client.properties")); + if (properties.containsKey("server")) server = properties.getProperty("server"); + if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); + localDB = new File(properties.getProperty("localDB", ".\\localDB")); + syncTimeout = Integer.parseInt(properties.getProperty("syncTimeout", "1000")); + } catch (Exception e) { + throw new EnvoyException("Failed to load client.properties", e); + } } /** @@ -47,9 +58,10 @@ public class Config { * -s, --port / -p and --localDB / -db. * * @param args the command line arguments to parse + * @throws EnvoyException if the command line arguments contain an unknown token * @since Envoy v0.1-alpha */ - public void load(String[] args) { + public void load(String[] args) throws EnvoyException { for (int i = 0; i < args.length; i++) switch (args[i]) { case "--server": @@ -64,6 +76,8 @@ public class Config { case "-db": localDB = new File(args[++i]); break; + default: + throw new EnvoyException("Unknown token " + args[i] + " found"); } } @@ -71,9 +85,7 @@ public class Config { * @return {@code true} if server, port and localDB directory are known. * @since Envoy v0.1-alpha */ - public boolean isInitialized() { - return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; - } + public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; } /** * @return the host name of the Envoy server @@ -114,7 +126,7 @@ public class Config { /** * Changes the default local database. * Exclusively intended for development purposes. - * + * * @param localDB the file containing the local database * @since Envoy v0.1-alpha **/ diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index c8373ed..48ce399 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -1,8 +1,6 @@ package envoy.client.ui; import java.awt.EventQueue; -import java.io.IOException; -import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; @@ -35,24 +33,19 @@ public class Startup { Config config = Config.getInstance(); - // Load the configuration from client.properties first - ClassLoader loader = Thread.currentThread().getContextClassLoader(); try { - Properties configProperties = new Properties(); - configProperties.load(loader.getResourceAsStream("client.properties")); - config.load(configProperties); - } catch (IOException e) { - e.printStackTrace(); - } + // Load the configuration from client.properties first + config.load(); - // Override configuration values with command line arguments - if (args.length > 0) config.load(args); + // Override configuration values with command line arguments + if (args.length > 0) config.load(args); - // Check if all configuration values have been initialized - if (!config.isInitialized()) { - logger.severe("Server or port are not defined. Exiting..."); - JOptionPane.showMessageDialog(null, "Error loading configuration values.", "Configuration error", JOptionPane.ERROR_MESSAGE); + // Check if all configuration values have been initialized + if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined"); + } catch (Exception e) { + JOptionPane.showMessageDialog(null, "Error loading configuration values: \n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE); System.exit(1); + e.printStackTrace(); } // Ask the user for their user name From f983b6ffe798815b3194196e51b58c00cbbd7bda Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 14 Dec 2019 08:44:03 +0100 Subject: [PATCH 101/474] Added user list serialization to LocalDB * Added user list to LocalDB * Removed client user from LocalDB constructor --- src/main/java/envoy/client/LocalDB.java | 108 +++++++++++++----- src/main/java/envoy/client/ui/ChatWindow.java | 2 +- src/main/java/envoy/client/ui/Startup.java | 3 +- 3 files changed, 80 insertions(+), 33 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index f061b28..2ab33ed 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -34,9 +34,11 @@ import envoy.schema.User; */ public class LocalDB { - private File localDB; - private User sender; - private List chats = new ArrayList<>(); + private File localDBFile, usersFile; + private User user; + private List users = new ArrayList<>(); + private List chats = new ArrayList<>(); + private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; @@ -44,16 +46,15 @@ public class LocalDB { private Sync sync = objectFactory.createSync(); private Sync readMessages = objectFactory.createSync(); - private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); + private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); /** - * Constructs an empty local database. + * Constructs an empty local database. To serialize any chats to the file + * system, call {@link LocalDB#initializeDBFile(File)}. * - * @param sender the user that is logged in with this client * @since Envoy v0.1-alpha */ - public LocalDB(User sender) { - this.sender = sender; + public LocalDB() { try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException e) { @@ -70,10 +71,17 @@ public class LocalDB { * @since Envoy v0.1-alpha */ public void initializeDBFile(File localDBDir) throws EnvoyException { + if (user == null) throw new NullPointerException("Client user is null"); if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - localDB = new File(localDBDir, sender.getID() + ".db"); - if (localDB.exists()) loadFromLocalDB(); + usersFile = new File(localDBDir, "users.db"); + localDBFile = new File(localDBDir, user.getID() + ".db"); + try { + loadUsers(); + loadChats(); + } catch (ClassNotFoundException | IOException e) { + throw new EnvoyException(e); + } } /** @@ -82,29 +90,46 @@ public class LocalDB { * @throws IOException if something went wrong during saving * @since Envoy v0.1-alpha */ - public void saveToLocalDB() throws IOException { - localDB.getParentFile().mkdirs(); - localDB.createNewFile(); - try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) { - out.writeObject(chats); - } catch (IOException ex) { - throw ex; - } + public void save() throws IOException { + // Save users + write(usersFile, users); + + // Save chats + write(localDBFile, chats); } + @SuppressWarnings("unchecked") + private void loadUsers() throws ClassNotFoundException, IOException { users = read(usersFile, ArrayList.class); } + /** * Loads all chats saved by Envoy for the client user. * - * @throws EnvoyException if something fails while loading. + * @throws EnvoyException if something fails while loading. + * @throws IOException + * @throws ClassNotFoundException * @since Envoy v0.1-alpha */ @SuppressWarnings("unchecked") - private void loadFromLocalDB() throws EnvoyException { - try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(localDB))) { - Object obj = in.readObject(); - if (obj instanceof ArrayList) chats = (ArrayList) obj; + private void loadChats() throws ClassNotFoundException, IOException { chats = read(localDBFile, ArrayList.class); } + + private T read(File file, Class serializedClass) throws ClassNotFoundException, IOException { + try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { + return serializedClass.cast(in.readObject()); } catch (ClassNotFoundException | IOException e) { - throw new EnvoyException(e); + throw e; + } + } + + private void write(File file, T obj) throws IOException { + if (file == null) throw new NullPointerException("File is null"); + if (!file.exists()) { + file.getParentFile().mkdirs(); + file.createNewFile(); + } + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) { + out.writeObject(obj); + } catch (IOException e) { + throw e; } } @@ -118,7 +143,7 @@ public class LocalDB { */ public Message createMessage(String textContent, long recipientID) { Message.Metadata metaData = objectFactory.createMessageMetadata(); - metaData.setSender(sender.getID()); + metaData.setSender(user.getID()); metaData.setRecipient(recipientID); metaData.setState(MessageState.WAITING); metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); @@ -134,13 +159,13 @@ public class LocalDB { return message; } - /** + /** * Creates a {@link Sync} object filled with the changes that occurred to the * local database since the last synchronization. * * @param userId the ID of the user that is synchronized by this client * @return {@link Sync} object filled with the current changes - * @since Envoy v0.1-alpha + * @since Envoy v0.1-alpha */ public Sync fillSync(long userId) { addWaitingMessagesToSync(); @@ -156,7 +181,7 @@ public class LocalDB { * Applies the changes carried by a {@link Sync} object to the local database * * @param returnSync the {@link Sync} object to apply - * @since Envoy v0.1-alpha + * @since Envoy v0.1-alpha */ public void applySync(Sync returnSync) { for (int i = 0; i < returnSync.getMessages().size(); i++) { @@ -280,6 +305,16 @@ public class LocalDB { */ public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } + /** + * @return the users + */ + public List getUsers() { return users; } + + /** + * @param users the users to set + */ + public void setUsers(List users) { this.users = users; } + /** * @return all saved {@link Chat} objects that list the client user as the * sender @@ -288,8 +323,19 @@ public class LocalDB { public List getChats() { return chats; } /** - * @return the {@link User} who initialized the local database - * @since Envoy v0.1-alpha + * @param chats the chats to set */ - public User getUser() { return sender; } + public void setChats(List chats) { this.chats = chats; } + + /** + * @return the {@link User} who initialized the local database + * @since Envoy v0.2-alpha + */ + public User getUser() { return user; } + + /** + * @param user the user to set + * @since Envoy v0.2-alpha + */ + public void setUser(User user) { this.user = user; } } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 6867f5e..ee32bf6 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -86,7 +86,7 @@ public class ChatWindow extends JFrame { @Override public void windowClosing(WindowEvent evt) { try { - localDB.saveToLocalDB(); + localDB.save(); Settings.getInstance().save(); } catch (IOException e1) { e1.printStackTrace(); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 48ce399..f0cf53e 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -68,7 +68,8 @@ public class Startup { } // Load the local database - LocalDB localDB = new LocalDB(client.getSender()); + LocalDB localDB = new LocalDB(); + localDB.setUser(client.getSender()); try { localDB.initializeDBFile(config.getLocalDB()); } catch (EnvoyException e) { From 27c420afdccb7d6539e8bad2c57ba99fa918122f Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 14 Dec 2019 09:58:25 +0100 Subject: [PATCH 102/474] Removed user id, name and email from Settings --- src/main/java/envoy/client/Client.java | 9 +- src/main/java/envoy/client/Settings.java | 43 --------- .../java/envoy/client/ui/SettingsScreen.java | 91 ++++--------------- src/main/java/envoy/client/ui/Startup.java | 7 +- 4 files changed, 20 insertions(+), 130 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index a6a7f36..fdf371d 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -38,9 +38,6 @@ public class Client { this.config = config; sender = getUser(userName); - // Update the user ID in the cache - Settings.getInstance().setUserID(sender.getID()); - logger.info("Client user ID: " + sender.getID()); } @@ -100,11 +97,7 @@ public class Client { return sync.getUsers().get(0); } else throw new EnvoyException("Unexpected response from Envoy Server"); } catch (Exception e) { - logger.warning("Could not connect to server, trying offline mode."); - if (Settings.getInstance().getUserID() != -1) { - user.setID(Settings.getInstance().getUserID()); - return user; - } else throw new EnvoyException("Could not enter offline mode."); + throw new EnvoyException("Could not connect to server", e); } } diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 851c936..714e5f7 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -26,9 +26,6 @@ import envoy.client.ui.Theme; public class Settings { // Actual settings accessible by the rest of the application - private String username; - private long userID; - private String email; private boolean enterToSend = true; private Map themes; private String currentTheme; @@ -66,9 +63,6 @@ public class Settings { @SuppressWarnings("unchecked") private void load() { - setUsername(prefs.get("username", "")); - setUserID(prefs.getLong("userID", -1)); - setEmail(prefs.get("email", "")); setEnterToSend(prefs.getBoolean("enterToSend", true)); setCurrentTheme(prefs.get("theme", "dark")); @@ -98,9 +92,6 @@ public class Settings { * @since Envoy v0.2-alpha */ public void save() throws IOException { - prefs.put("username", getUsername()); - prefs.putLong("userID", getUserID()); - prefs.put("email", getEmail()); prefs.put("theme", currentTheme); prefs.putBoolean("enterToSend", isEnterToSend()); @@ -136,40 +127,6 @@ public class Settings { */ public void setCurrentTheme(String themeName) { currentTheme = themeName; } - /** - * @return the user name - * @since Envoy v0.2-alpha - */ - public String getUsername() { return username; } - - /** - * @param username the user name to set - * @since Envoy v0.2-alpha - */ - public void setUsername(String username) { this.username = username; } - - /** - * @return the userID - */ - public long getUserID() { return userID; } - - /** - * @param userID the userID to set - */ - public void setUserID(long userID) { this.userID = userID; } - - /** - * @return the email associated with that user. - * @since Envoy v0.2-alpha - */ - public String getEmail() { return email; } - - /** - * @param email the email to set - * @since Envoy v0.2-alpha - */ - public void setEmail(String email) { this.email = email; } - /** * @return true, if "enter" suffices to send a message, else it has to be "ctrl" * + "enter" diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index bd80c2e..fdc12dc 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -101,8 +101,7 @@ public class SettingsScreen extends JDialog { createNewThemeButton.setEnabled(false); - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); // Content pane GridBagLayout gbl_contentPanel = new GridBagLayout(); @@ -200,20 +199,8 @@ public class SettingsScreen extends JDialog { colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getBackgroundColor(), - "Background", - 1); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getCellColor(), - "Cells", - 2); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getBackgroundColor(), "Background", 1); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getCellColor(), "Cells", 2); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), @@ -228,41 +215,11 @@ public class SettingsScreen extends JDialog { theme.getInteractableBackgroundColor(), "Interactable Background", 4); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getMessageColorChat(), - "Messages Chat", - 5); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getDateColorChat(), - "Date Chat", - 6); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getSelectionColor(), - "Selection", - 7); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getTypingMessageColor(), - "Typing Message", - 8); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getUserNameColor(), - "User Names", - 9); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getMessageColorChat(), "Messages Chat", 5); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getDateColorChat(), "Date Chat", 6); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getSelectionColor(), "Selection", 7); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getTypingMessageColor(), "Typing Message", 8); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getUserNameColor(), "User Names", 9); GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; @@ -283,16 +240,14 @@ public class SettingsScreen extends JDialog { String s = JOptionPane.showInputDialog("Enter a name for the new theme"); System.out.println(s); Settings.getInstance() - .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), - temporaryTheme.getCellColor(), temporaryTheme.getInteractableForegroundColor(), - temporaryTheme.getInteractableBackgroundColor(), temporaryTheme.getMessageColorChat(), - temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), + .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(), + temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(), + temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor())); themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName(); - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); createNewThemeButton.setEnabled(false); themes.addItem(themeArray[themeArray.length - 1]); @@ -348,10 +303,6 @@ public class SettingsScreen extends JDialog { getRootPane().setDefaultButton(okButton); okButton.addActionListener((evt) -> { try { - Settings.getInstance().setUsername(Settings.getInstance().getUsername());// still temporary - - Settings.getInstance().setEmail(Settings.getInstance().getEmail());// still temporary value - Settings.getInstance().setEnterToSend(Settings.getInstance().isEnterToSend());// still temporary Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); @@ -412,21 +363,12 @@ public class SettingsScreen extends JDialog { temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getInteractableForegroundColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getInteractableBackgroundColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableForegroundColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getSelectionColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getTypingMessageColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getTypingMessageColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); colorsPanel.removeAll(); @@ -513,8 +455,7 @@ public class SettingsScreen extends JDialog { private void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); } - private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, - String name, int yIndex) { + private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, String name, int yIndex) { textPane.setFont(new Font("Arial", Font.PLAIN, 14)); textPane.setBackground(theme.getBackgroundColor()); textPane.setForeground(theme.getUserNameColor()); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index f0cf53e..b9d08c4 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -9,7 +9,6 @@ import javax.swing.JOptionPane; import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; -import envoy.client.Settings; import envoy.exception.EnvoyException; /** @@ -43,7 +42,8 @@ public class Startup { // Check if all configuration values have been initialized if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined"); } catch (Exception e) { - JOptionPane.showMessageDialog(null, "Error loading configuration values: \n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE); + JOptionPane + .showMessageDialog(null, "Error loading configuration values: \n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE); System.exit(1); e.printStackTrace(); } @@ -56,7 +56,7 @@ public class Startup { } // Acquire the client user (with ID) either from the server or from the local - // cache (Preferences), which triggers offline mode + // database, which triggers offline mode Client client; try { client = new Client(config, userName); @@ -79,7 +79,6 @@ public class Startup { "Local DB error", JOptionPane.WARNING_MESSAGE); } - Settings.getInstance().setUsername(userName); EventQueue.invokeLater(() -> { try { From 2eb9c79106b4b66a03e1644ecb8f2b1b67873fd5 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 14 Dec 2019 10:53:20 +0100 Subject: [PATCH 103/474] Implemented offline mode for Client and LocalDB --- src/main/java/envoy/client/Client.java | 28 +++++---- src/main/java/envoy/client/LocalDB.java | 34 +++++------ src/main/java/envoy/client/ui/ChatWindow.java | 31 ++++------ src/main/java/envoy/client/ui/Startup.java | 57 ++++++++++++++----- 4 files changed, 87 insertions(+), 63 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index fdf371d..356dc24 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,6 +1,7 @@ package envoy.client; -import java.util.logging.Logger; +import java.util.HashMap; +import java.util.Map; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; @@ -32,13 +33,11 @@ public class Client { private User sender, recipient; private boolean online = false; - private static final Logger logger = Logger.getLogger(Client.class.getSimpleName()); + public Client(Config config) { this.config = config; } - public Client(Config config, String userName) throws EnvoyException { - this.config = config; - sender = getUser(userName); - - logger.info("Client user ID: " + sender.getID()); + public void onlineInit(String userName) throws EnvoyException { + sender = getUser(userName); + online = true; } private R post(String uri, T body, Class responseBodyClass) { @@ -53,22 +52,25 @@ public class Client { } /** - * Returns a {@link Sync} with all users on the server. + * Returns a {@code Map} of all users on the server with their + * user names as keys. * * @return Sync - List of all users on the server. - * @since Envoy v0.1-alpha + * @since Envoy v0.2-alpha */ - public Sync getUsersListXml() { + public Map getUsers() { Sync sendSync = objectFactory.createSync(); User user = objectFactory.createUser(); user.setID(-1); sendSync.getUsers().add(user); - Sync returnSendSync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + Sync returnSync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), sendSync, Sync.class); - return returnSendSync; + Map users = new HashMap<>(); + returnSync.getUsers().forEach(u -> users.put(u.getName(), u)); + return users; } /** @@ -160,6 +162,8 @@ public class Client { */ public User getSender() { return sender; } + public void setSender(User sender) { this.sender = sender; } + /** * @return the current recipient of the current chat. * @since Envoy v0.1-alpha diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 2ab33ed..f22c7c7 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -8,7 +8,9 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.time.Instant; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.logging.Logger; import javax.xml.datatype.DatatypeConfigurationException; @@ -34,9 +36,9 @@ import envoy.schema.User; */ public class LocalDB { - private File localDBFile, usersFile; + private File localDBDir, localDBFile, usersFile; private User user; - private List users = new ArrayList<>(); + private Map users = new HashMap<>(); private List chats = new ArrayList<>(); private ObjectFactory objectFactory = new ObjectFactory(); @@ -54,12 +56,19 @@ public class LocalDB { * * @since Envoy v0.1-alpha */ - public LocalDB() { + public LocalDB(File localDBDir) throws IOException { + this.localDBDir = localDBDir; + try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException e) { e.printStackTrace(); } + + // Initialize local database directory + if (localDBDir.exists() && !localDBDir.isDirectory()) + throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); + usersFile = new File(localDBDir, "users.db"); } /** @@ -70,18 +79,9 @@ public class LocalDB { * @throws EnvoyException if the directory selected is not an actual directory. * @since Envoy v0.1-alpha */ - public void initializeDBFile(File localDBDir) throws EnvoyException { + public void initializeDBFile() throws EnvoyException { if (user == null) throw new NullPointerException("Client user is null"); - if (localDBDir.exists() && !localDBDir.isDirectory()) - throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - usersFile = new File(localDBDir, "users.db"); localDBFile = new File(localDBDir, user.getID() + ".db"); - try { - loadUsers(); - loadChats(); - } catch (ClassNotFoundException | IOException e) { - throw new EnvoyException(e); - } } /** @@ -99,7 +99,7 @@ public class LocalDB { } @SuppressWarnings("unchecked") - private void loadUsers() throws ClassNotFoundException, IOException { users = read(usersFile, ArrayList.class); } + public void loadUsers() throws ClassNotFoundException, IOException { users = read(usersFile, HashMap.class); } /** * Loads all chats saved by Envoy for the client user. @@ -110,7 +110,7 @@ public class LocalDB { * @since Envoy v0.1-alpha */ @SuppressWarnings("unchecked") - private void loadChats() throws ClassNotFoundException, IOException { chats = read(localDBFile, ArrayList.class); } + public void loadChats() throws ClassNotFoundException, IOException { chats = read(localDBFile, ArrayList.class); } private T read(File file, Class serializedClass) throws ClassNotFoundException, IOException { try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { @@ -308,12 +308,12 @@ public class LocalDB { /** * @return the users */ - public List getUsers() { return users; } + public Map getUsers() { return users; } /** * @param users the users to set */ - public void setUsers(List users) { this.users = users; } + public void setUsers(Map users) { this.users = users; } /** * @return all saved {@link Chat} objects that list the client user as the diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index ee32bf6..0c85abb 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -34,7 +34,6 @@ import envoy.client.Config; import envoy.client.LocalDB; import envoy.client.Settings; import envoy.schema.Message; -import envoy.schema.Sync; import envoy.schema.User; /** @@ -132,8 +131,7 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER - && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) - || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); } } @@ -181,8 +179,8 @@ public class ChatWindow extends JFrame { settingsButton.addActionListener((evt) -> { try { SettingsScreen.open(); - changeChatWindowColors(Settings.getInstance().getCurrentTheme()); - } catch (Exception e) { + changeChatWindowColors(Settings.getInstance().getCurrentTheme()); + } catch (Exception e) { SettingsScreen.open(); logger.log(Level.WARNING, "An error occured while opening the settings screen", e); e.printStackTrace(); @@ -235,7 +233,7 @@ public class ChatWindow extends JFrame { gbc_userList.insets = new Insets(space, space, space, space); changeChatWindowColors(Settings.getInstance().getCurrentTheme()); - + contentPane.add(userList, gbc_userList); contentPane.revalidate(); @@ -244,7 +242,6 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); } - /** * Used to immediately reload the ChatWindow when settings were changed. @@ -287,18 +284,14 @@ public class ChatWindow extends JFrame { private void postMessage(JList messageList) { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, - "Please select a recipient!", - "Cannot send message", - JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); return; } if (!messageEnterTextArea.getText().isEmpty()) try { // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), - currentChat.getRecipient().getID()); + final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient().getID()); currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); @@ -322,9 +315,8 @@ public class ChatWindow extends JFrame { */ private void loadUsersAndChats() { new Thread(() -> { - Sync users = client.getUsersListXml(); - DefaultListModel userListModel = new DefaultListModel<>(); - users.getUsers().forEach(user -> { + DefaultListModel userListModel = new DefaultListModel<>(); + localDB.getUsers().values().forEach(user -> { userListModel.addElement(user); // Check if user exists in local DB @@ -348,8 +340,7 @@ public class ChatWindow extends JFrame { new Thread(() -> { // Synchronize - localDB.applySync( - client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); // Process unread messages localDB.addUnreadMessagesToLocalDB(); @@ -359,8 +350,7 @@ public class ChatWindow extends JFrame { readCurrentChat(); // Update UI - SwingUtilities - .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); + SwingUtilities.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); }).start(); }).start(); } @@ -377,4 +367,3 @@ public class ChatWindow extends JFrame { */ private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } } - diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index b9d08c4..e2f6b5e 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -1,6 +1,7 @@ package envoy.client.ui; import java.awt.EventQueue; +import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -10,6 +11,7 @@ import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; import envoy.exception.EnvoyException; +import envoy.schema.User; /** * Starts the Envoy client and prompts the user to enter their name. @@ -54,32 +56,61 @@ public class Startup { logger.severe("User name is not set or empty. Exiting..."); System.exit(1); } - - // Acquire the client user (with ID) either from the server or from the local - // database, which triggers offline mode - Client client; + + // Initialize the local database + LocalDB localDB; try { - client = new Client(config, userName); - } catch (Exception e1) { - logger.log(Level.SEVERE, "Failed to acquire client user ID", e1); - JOptionPane.showMessageDialog(null, e1.toString(), "Client error", JOptionPane.ERROR_MESSAGE); + localDB = new LocalDB(config.getLocalDB()); + } catch (IOException e3) { + logger.log(Level.SEVERE, "Could not initialize local database", e3); + JOptionPane.showMessageDialog(null, "Could not initialize local database!\n" + e3.toString()); System.exit(1); return; } - // Load the local database - LocalDB localDB = new LocalDB(); - localDB.setUser(client.getSender()); + // Acquire the client user (with ID) either from the server or from the local + // database, which triggers offline mode + Client client = new Client(config); try { - localDB.initializeDBFile(config.getLocalDB()); - } catch (EnvoyException e) { + // Try entering online mode first + client.onlineInit(userName); + } catch (Exception e1) { + logger.warning("Could not connect to server. Trying offline mode..."); + try { + // Try entering offline mode + localDB.loadUsers(); + User clientUser = localDB.getUsers().get(userName); + if(clientUser == null) + throw new EnvoyException("Could not enter offline mode: user name unknown"); + client.setSender(clientUser); + } catch(Exception e2) { + JOptionPane.showMessageDialog(null, e1.toString(), "Client error", JOptionPane.ERROR_MESSAGE); + System.exit(1); + return; + } + } + + // Set client user in local database + localDB.setUser(client.getSender()); + + // Initialize chats in local database + try { + localDB.initializeDBFile(); + localDB.loadChats(); + } catch (EnvoyException | ClassNotFoundException | IOException e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", "Local DB error", JOptionPane.WARNING_MESSAGE); } + + logger.info("Client user ID: " + client.getSender().getID()); + // Save all users to the local database + if(client.isOnline()) + localDB.setUsers(client.getUsers()); + EventQueue.invokeLater(() -> { try { ChatWindow chatWindow = new ChatWindow(client, localDB); From fb3b53efd8e5ed698729c379d9bc73fef22aed6b Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 14 Dec 2019 11:02:01 +0100 Subject: [PATCH 104/474] Not starting the sync thread in offline mode --- src/main/java/envoy/client/ui/ChatWindow.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 0c85abb..ab0cbb7 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -238,7 +238,9 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); loadUsersAndChats(); - startSyncThread(Config.getInstance().getSyncTimeout()); + + if(client.isOnline()) + startSyncThread(Config.getInstance().getSyncTimeout()); contentPane.revalidate(); } From 6ab38e1e1a269d46b154d864aa1301025b8fcdf9 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 14 Dec 2019 11:22:37 +0100 Subject: [PATCH 105/474] Fixes bugs with the incorrect applying of the changed colors. Fixes #50 --- src/main/java/envoy/client/Settings.java | 2 +- .../java/envoy/client/ui/SettingsScreen.java | 60 ++++++++----------- src/main/java/envoy/client/ui/Theme.java | 23 +------ 3 files changed, 28 insertions(+), 57 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 91f696f..3bd54f1 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -116,7 +116,7 @@ public class Settings { */ public void addNewThemeToMap(Theme theme) { settings.getThemes().put(theme.getThemeName(), theme); - currentTheme = theme.getThemeName(); + // currentTheme = theme.getThemeName(); } /** diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index bd80c2e..f96eac1 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -206,63 +206,63 @@ public class SettingsScreen extends JDialog { theme, theme.getBackgroundColor(), "Background", - 1); + 0); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getCellColor(), "Cells", - 2); + 1); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getInteractableForegroundColor(), "Interactable Foreground", - 3); + 2); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getInteractableBackgroundColor(), "Interactable Background", - 4); + 3); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getMessageColorChat(), "Messages Chat", - 5); + 4); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getDateColorChat(), "Date Chat", - 6); + 5); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getSelectionColor(), "Selection", - 7); + 6); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getTypingMessageColor(), "Typing Message", - 8); + 7); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getUserNameColor(), "User Names", - 9); + 8); GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; @@ -438,7 +438,7 @@ public class SettingsScreen extends JDialog { theme, theme.getBackgroundColor(), "Background", - 1); + 0); buildCustomizeElement(new JPanel(), new JButton(), @@ -446,7 +446,7 @@ public class SettingsScreen extends JDialog { theme, theme.getCellColor(), "Cells", - 2); + 1); buildCustomizeElement(new JPanel(), new JButton(), @@ -454,7 +454,7 @@ public class SettingsScreen extends JDialog { theme, theme.getInteractableForegroundColor(), "Interactable Foreground", - 3); + 2); buildCustomizeElement(new JPanel(), new JButton(), @@ -462,7 +462,7 @@ public class SettingsScreen extends JDialog { theme, theme.getInteractableBackgroundColor(), "Interactable Background", - 4); + 3); buildCustomizeElement(new JPanel(), new JButton(), @@ -470,7 +470,7 @@ public class SettingsScreen extends JDialog { theme, theme.getMessageColorChat(), "Messages Chat", - 5); + 4); buildCustomizeElement(new JPanel(), new JButton(), @@ -478,7 +478,7 @@ public class SettingsScreen extends JDialog { theme, theme.getDateColorChat(), "Date Chat", - 6); + 5); buildCustomizeElement(new JPanel(), new JButton(), @@ -486,7 +486,7 @@ public class SettingsScreen extends JDialog { theme, theme.getSelectionColor(), "Selection", - 7); + 6); buildCustomizeElement(new JPanel(), new JButton(), @@ -494,7 +494,7 @@ public class SettingsScreen extends JDialog { theme, theme.getTypingMessageColor(), "Typing Message", - 8); + 7); buildCustomizeElement(new JPanel(), new JButton(), @@ -502,7 +502,7 @@ public class SettingsScreen extends JDialog { theme, theme.getUserNameColor(), "User Names", - 9); + 8); GridBagConstraints gbc_createNewTheme = new GridBagConstraints(); gbc_createNewTheme.gridx = 0; @@ -532,18 +532,11 @@ public class SettingsScreen extends JDialog { System.out.println(color.getRGB()); // TODO: When Theme changed in same settings screen, color variable doesnt // update. - Color[] colorsArray = temporaryTheme.getAllColors(); - for (int i = 0; i < colorsArray.length; i++) { - if (color.getRGB() == colorsArray[i].getRGB()) { - temporaryTheme.setColor(i, newColor); - colorChanged = true; - createNewThemeButton.setEnabled(true); - break; - } - - } + temporaryTheme.setColor(yIndex, newColor); + colorChanged = true; + createNewThemeButton.setEnabled(true); + } button.setBackground(newColor); - } } catch (Exception e) { logger.info("An error occured while opening Color Chooser: " + e); @@ -551,12 +544,9 @@ public class SettingsScreen extends JDialog { } }); - panel.add(textPane); - panel.add(button); - panel.setBackground(theme.getCellColor()); - panel.setAlignmentX(Component.LEFT_ALIGNMENT); + panel.add(textPane);panel.add(button);panel.setBackground(theme.getCellColor());panel.setAlignmentX(Component.LEFT_ALIGNMENT); - colorsPanel.add(panel); - } + colorsPanel.add(panel); +} } diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index a0ef259..9dcda1e 100644 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -44,8 +44,8 @@ public class Theme implements Serializable { } public Theme(String name, Theme other) { - this(name, other.backgroundColor, other.cellColor, other.interactableBackgroundColor, - other.interactableForegroundColor, other.messageColorChat, other.dateColorChat, other.selectionColor, + this(name, other.backgroundColor, other.cellColor, other.interactableForegroundColor, + other.interactableBackgroundColor, other.messageColorChat, other.dateColorChat, other.selectionColor, other.typingMessageColor, other.userNameColor); } @@ -109,25 +109,6 @@ public class Theme implements Serializable { */ public Color getUserNameColor() { return userNameColor; } - /** - * @return a color array containing all colors of this theme - * @since Envoy v0.2-alpha - */ - public Color[] getAllColors() { - Color[] c = new Color[9]; - c[0] = backgroundColor; - c[1] = cellColor; - c[2] = interactableForegroundColor; - c[3] = interactableBackgroundColor; - c[4] = messageColorChat; - c[5] = dateColorChat; - c[6] = selectionColor; - c[7] = typingMessageColor; - c[8] = userNameColor; - - return c; - } - /** * Sets the a specific {@link Color} in this theme to a new {@link Color} * From f044c5cc8d6a98e0a9749267760cc28650e6e842 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 14 Dec 2019 11:30:00 +0100 Subject: [PATCH 106/474] Added documentation, refined exception handling --- src/main/java/envoy/client/Client.java | 35 ++++++++++--- src/main/java/envoy/client/LocalDB.java | 49 +++++++++++-------- src/main/java/envoy/client/ui/ChatWindow.java | 11 +++-- src/main/java/envoy/client/ui/Startup.java | 2 +- 4 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 356dc24..b7cc83c 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -33,8 +33,23 @@ public class Client { private User sender, recipient; private boolean online = false; + /** + * Initializes the client. At this state, the client user has yet to be + * initialized, which can be done by calling {@link Client#onlineInit(String). + * + * @param config The {@link Config} instance to use in this client + * @since Envoy v0.2-alpha + */ public Client(Config config) { this.config = config; } + /** + * Enters the online mode by acquiring a user ID from the server. + * + * @param userName the name of the client user + * @throws EnvoyException if the online mode could not be entered or the request + * failed for some other reason + * @since Envoy v0.2-alpha + */ public void onlineInit(String userName) throws EnvoyException { sender = getUser(userName); online = true; @@ -52,10 +67,8 @@ public class Client { } /** - * Returns a {@code Map} of all users on the server with their - * user names as keys. - * - * @return Sync - List of all users on the server. + * @return a {@code Map} of all users on the server with their + * user names as keys * @since Envoy v0.2-alpha */ public Map getUsers() { @@ -138,9 +151,12 @@ public class Client { * @param sync the sync object (yet to be converted from java class to * sync.xml) * @return a returnSync.xml file + * @throws EnvoyException if the client is not in online mode * @since Envoy v0.1-alpha */ - public Sync sendSync(long userId, Sync sync) { + public Sync sendSync(long userId, Sync sync) throws EnvoyException { + if(!isOnline()) + throw new EnvoyException("Client is not in online mode"); // Print sync XML to console JAXBContext jc; try { @@ -162,6 +178,12 @@ public class Client { */ public User getSender() { return sender; } + /** + * Sets the client user which is used to send messages. + * + * @param sender the client user to set + * @since Envoy v0.2-alpha + */ public void setSender(User sender) { this.sender = sender; } /** @@ -173,7 +195,7 @@ public class Client { /** * Sets the recipient. * - * @param recipient - the recipient to set + * @param recipient the recipient to set * @since Envoy v0.1-alpha */ public void setRecipient(User recipient) { this.recipient = recipient; } @@ -186,6 +208,7 @@ public class Client { /** * @return {@code true} if a connection to the server could be established + * @since Envoy v0.2-alpha */ public boolean isOnline() { return online; } } diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index f22c7c7..60de119 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -36,10 +36,10 @@ import envoy.schema.User; */ public class LocalDB { - private File localDBDir, localDBFile, usersFile; - private User user; + private File localDBDir, localDBFile, usersFile; + private User user; private Map users = new HashMap<>(); - private List chats = new ArrayList<>(); + private List chats = new ArrayList<>(); private ObjectFactory objectFactory = new ObjectFactory(); private DatatypeFactory datatypeFactory; @@ -54,38 +54,38 @@ public class LocalDB { * Constructs an empty local database. To serialize any chats to the file * system, call {@link LocalDB#initializeDBFile(File)}. * + * @param localDBDir the directory in which to store users and chats * @since Envoy v0.1-alpha */ public LocalDB(File localDBDir) throws IOException { this.localDBDir = localDBDir; - + try { datatypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException e) { e.printStackTrace(); } - + // Initialize local database directory if (localDBDir.exists() && !localDBDir.isDirectory()) throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - usersFile = new File(localDBDir, "users.db"); + usersFile = new File(localDBDir, "users.db"); } /** - * Initializes the local database and fills it with values - * if the user has already sent or received messages. + * Creates a database file for a user-specific list of chats. * - * @param localDBDir the directory where we wish to save/load the database from. - * @throws EnvoyException if the directory selected is not an actual directory. + * @throws NullPointerException if the client user is not yet specified * @since Envoy v0.1-alpha */ - public void initializeDBFile() throws EnvoyException { + public void initializeDBFile() { if (user == null) throw new NullPointerException("Client user is null"); - localDBFile = new File(localDBDir, user.getID() + ".db"); + localDBFile = new File(localDBDir, user.getID() + ".db"); } /** - * Saves the database into a file for future use. + * Stores all users to the local database. If the client user is specified, the + * chats related to this user are stored as well. * * @throws IOException if something went wrong during saving * @since Envoy v0.1-alpha @@ -98,30 +98,36 @@ public class LocalDB { write(localDBFile, chats); } + /** + * Loads all users that are stored in the local database. + * + * @throws EnvoyException if the loading process failed + * @since Envoy v0.2-alpha + */ @SuppressWarnings("unchecked") - public void loadUsers() throws ClassNotFoundException, IOException { users = read(usersFile, HashMap.class); } + public void loadUsers() throws EnvoyException { users = read(usersFile, HashMap.class); } /** * Loads all chats saved by Envoy for the client user. * - * @throws EnvoyException if something fails while loading. - * @throws IOException - * @throws ClassNotFoundException + * @throws EnvoyException if the loading process failed * @since Envoy v0.1-alpha */ @SuppressWarnings("unchecked") - public void loadChats() throws ClassNotFoundException, IOException { chats = read(localDBFile, ArrayList.class); } + public void loadChats() throws EnvoyException { chats = read(localDBFile, ArrayList.class); } - private T read(File file, Class serializedClass) throws ClassNotFoundException, IOException { + private T read(File file, Class serializedClass) throws EnvoyException { + if (file == null) throw new NullPointerException("File is null"); try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { return serializedClass.cast(in.readObject()); } catch (ClassNotFoundException | IOException e) { - throw e; + throw new EnvoyException("Could not load serialized object", e); } } private void write(File file, T obj) throws IOException { if (file == null) throw new NullPointerException("File is null"); + if (obj == null) throw new NullPointerException("Object to serialize is null"); if (!file.exists()) { file.getParentFile().mkdirs(); file.createNewFile(); @@ -306,7 +312,8 @@ public class LocalDB { public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } /** - * @return the users + * @return a {@code Map} of all users stored locally with their user names as keys + * @since Envoy v0.2-alpha */ public Map getUsers() { return users; } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index ab0cbb7..45d607b 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -238,9 +238,8 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); loadUsersAndChats(); - - if(client.isOnline()) - startSyncThread(Config.getInstance().getSyncTimeout()); + + if (client.isOnline()) startSyncThread(Config.getInstance().getSyncTimeout()); contentPane.revalidate(); } @@ -342,7 +341,11 @@ public class ChatWindow extends JFrame { new Thread(() -> { // Synchronize - localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + try { + localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + } catch (Exception e) { + logger.log(Level.SEVERE, "Could not perform sync", e); + } // Process unread messages localDB.addUnreadMessagesToLocalDB(); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index e2f6b5e..933890d 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -97,7 +97,7 @@ public class Startup { try { localDB.initializeDBFile(); localDB.loadChats(); - } catch (EnvoyException | ClassNotFoundException | IOException e) { + } catch (EnvoyException e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", From 59dff7bf25f41f4f9b455351cbf56bf4b1751bc6 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 14 Dec 2019 12:54:32 +0100 Subject: [PATCH 107/474] Changed colors management in the displaying of the themes settings screen. --- .../java/envoy/client/ui/SettingsScreen.java | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index f96eac1..ef1dadc 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -138,11 +138,6 @@ public class SettingsScreen extends JDialog { Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - options.setSelectionForeground(theme.getUserNameColor()); - options.setSelectionBackground(theme.getSelectionColor()); - options.setForeground(theme.getUserNameColor()); - options.setBackground(theme.getCellColor()); - GridBagConstraints gbc_optionsList = new GridBagConstraints(); gbc_optionsList.fill = GridBagConstraints.BOTH; gbc_optionsList.gridx = 0; @@ -164,9 +159,6 @@ public class SettingsScreen extends JDialog { GridBagLayout gbl_themeLayout = new GridBagLayout(); - themeContent.setForeground(theme.getUserNameColor()); - themeContent.setBackground(theme.getCellColor()); - gbl_themeLayout.columnWidths = new int[] { 1, 1 }; gbl_themeLayout.rowHeights = new int[] { 1, 1 }; gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 }; @@ -174,8 +166,6 @@ public class SettingsScreen extends JDialog { themeContent.setLayout(gbl_themeLayout); - themes.setBackground(theme.getUserNameColor()); - themes.setForeground(theme.getBackgroundColor()); themes.setSelectedItem(Settings.getInstance().getCurrentTheme()); themes.addItemListener(new ItemListener() { @@ -300,8 +290,6 @@ public class SettingsScreen extends JDialog { contentPanel.revalidate(); contentPanel.repaint(); - // TODO: Create new Theme - } catch (Exception e) { logger.info("New theme couldn't be created! " + e); e.printStackTrace(); @@ -397,8 +385,8 @@ public class SettingsScreen extends JDialog { themeContent.setForeground(theme.getUserNameColor()); themeContent.setBackground(theme.getCellColor()); // themes - themes.setBackground(theme.getUserNameColor()); - themes.setForeground(theme.getBackgroundColor()); + themes.setBackground(theme.getBackgroundColor()); + themes.setForeground(getInvertedColor(theme.getBackgroundColor())); createNewThemeButton.setBackground(theme.getInteractableBackgroundColor()); createNewThemeButton.setForeground(theme.getInteractableForegroundColor()); @@ -517,7 +505,7 @@ public class SettingsScreen extends JDialog { String name, int yIndex) { textPane.setFont(new Font("Arial", Font.PLAIN, 14)); textPane.setBackground(theme.getBackgroundColor()); - textPane.setForeground(theme.getUserNameColor()); + textPane.setForeground(getInvertedColor(theme.getBackgroundColor())); textPane.setText(name); textPane.setEditable(false); @@ -532,11 +520,11 @@ public class SettingsScreen extends JDialog { System.out.println(color.getRGB()); // TODO: When Theme changed in same settings screen, color variable doesnt // update. - temporaryTheme.setColor(yIndex, newColor); - colorChanged = true; - createNewThemeButton.setEnabled(true); - } - button.setBackground(newColor); + temporaryTheme.setColor(yIndex, newColor); + colorChanged = true; + createNewThemeButton.setEnabled(true); + } + button.setBackground(newColor); } catch (Exception e) { logger.info("An error occured while opening Color Chooser: " + e); @@ -544,9 +532,16 @@ public class SettingsScreen extends JDialog { } }); - panel.add(textPane);panel.add(button);panel.setBackground(theme.getCellColor());panel.setAlignmentX(Component.LEFT_ALIGNMENT); + panel.add(textPane); + panel.add(button); + panel.setBackground(theme.getCellColor()); + panel.setAlignmentX(Component.LEFT_ALIGNMENT); - colorsPanel.add(panel); -} + colorsPanel.add(panel); + } + + private Color getInvertedColor(Color color) { + return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); + } } From 507e24951218b3667c47be38fe86849d6021acef Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 14 Dec 2019 13:46:19 +0100 Subject: [PATCH 108/474] Revised code according to reviews by @delvh and @CyB3RC0nN0R --- src/main/java/envoy/client/ui/ChatWindow.java | 40 +++++++++---------- .../java/envoy/client/ui/PrimaryButton.java | 3 +- .../java/envoy/client/ui/PrimaryTextArea.java | 9 +++-- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 14065b0..1434148 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -53,16 +53,16 @@ public class ChatWindow extends JFrame { private Client client; private LocalDB localDB; // GUI components - private JPanel contentPane = new JPanel(); - private PrimaryTextArea messageEnterTextArea; - private JList userList = new JList<>(); + private JPanel contentPane = new JPanel(); + private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); + private JList userList = new JList<>(); private Chat currentChat; - private JList messageList = new JList<>(); - private JScrollPane scrollPane = new JScrollPane(); - private JTextPane textPane = new JTextPane(); + private JList messageList = new JList<>(); + private JScrollPane scrollPane = new JScrollPane(); + private JTextPane textPane = new JTextPane(); // private JCheckBox jCbChangeMode; - private PrimaryButton postButton; - private PrimaryButton settingsButton; + private PrimaryButton postButton = new PrimaryButton("Post"); + private PrimaryButton settingsButton = new PrimaryButton("Settings"); private static int space = 4; @@ -76,7 +76,8 @@ public class ChatWindow extends JFrame { setBounds(100, 100, 600, 800); setTitle("Envoy"); setLocationRelativeTo(null); - setIconImage(Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); + setIconImage( + Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); // Save chats when window closes addWindowListener(new WindowAdapter() { @@ -124,9 +125,6 @@ public class ChatWindow extends JFrame { gbc_scrollPane.insets = new Insets(space, space, space, space); contentPane.add(scrollPane, gbc_scrollPane); - // Checks for changed Message - messageEnterTextArea = new PrimaryTextArea(space); - // Message enter field messageEnterTextArea.addKeyListener(new KeyAdapter() { @@ -140,7 +138,6 @@ public class ChatWindow extends JFrame { } }); - GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; gbc_messageEnterTextfield.gridx = 1; @@ -151,7 +148,6 @@ public class ChatWindow extends JFrame { contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); // Post Button - postButton = new PrimaryButton("Post"); GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; @@ -164,8 +160,6 @@ public class ChatWindow extends JFrame { contentPane.add(postButton, gbc_moveSelectionPostButton); // Settings Button - settingsButton = new PrimaryButton("Settings"); - GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); gbc_moveSelectionSettingsButton.fill = GridBagConstraints.BOTH; @@ -177,8 +171,8 @@ public class ChatWindow extends JFrame { settingsButton.addActionListener((evt) -> { try { SettingsScreen.open(); - changeChatWindowColors(Settings.getInstance().getCurrentTheme()); - } catch (Exception e) { + changeChatWindowColors(Settings.getInstance().getCurrentTheme()); + } catch (Exception e) { SettingsScreen.open(); logger.log(Level.WARNING, "An error occured while opening the settings screen", e); e.printStackTrace(); @@ -207,7 +201,11 @@ public class ChatWindow extends JFrame { final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); + currentChat = localDB.getChats() + .stream() + .filter(chat -> chat.getRecipient().getID() == user.getID()) + .findFirst() + .get(); // Set all unread messages in the chat to read readCurrentChat(); @@ -231,7 +229,7 @@ public class ChatWindow extends JFrame { gbc_userList.insets = new Insets(space, space, space, space); changeChatWindowColors(Settings.getInstance().getCurrentTheme()); - + contentPane.add(userList, gbc_userList); contentPane.revalidate(); @@ -240,7 +238,6 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); } - /** * Used to immediately reload the ChatWindow when settings were changed. @@ -373,4 +370,3 @@ public class ChatWindow extends JFrame { */ private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } } - diff --git a/src/main/java/envoy/client/ui/PrimaryButton.java b/src/main/java/envoy/client/ui/PrimaryButton.java index 2e528db..fe93571 100644 --- a/src/main/java/envoy/client/ui/PrimaryButton.java +++ b/src/main/java/envoy/client/ui/PrimaryButton.java @@ -11,6 +11,7 @@ import javax.swing.JButton; * * @author Kai S. K. Engelbart * @author Maximilian Käfer + * @since Envoy v0.2-alpha */ public class PrimaryButton extends JButton { @@ -35,8 +36,6 @@ public class PrimaryButton extends JButton { */ public PrimaryButton(String title, int arcSize) { super(title); - // setForeground(new Color(255, 255, 255)); - // setBackground(new Color(102, 51, 153)); setBorderPainted(false); setFocusPainted(false); setContentAreaFilled(false); diff --git a/src/main/java/envoy/client/ui/PrimaryTextArea.java b/src/main/java/envoy/client/ui/PrimaryTextArea.java index 3f350ed..e4d6fa1 100644 --- a/src/main/java/envoy/client/ui/PrimaryTextArea.java +++ b/src/main/java/envoy/client/ui/PrimaryTextArea.java @@ -12,6 +12,7 @@ import javax.swing.border.EmptyBorder; * Created: 07.12.2019
* * @author Maximilian Käfer + * @since Envoy v0.2-alpha */ public class PrimaryTextArea extends JTextArea { @@ -20,7 +21,7 @@ public class PrimaryTextArea extends JTextArea { private int arcSize; /** - * Creates TextArea + * Creates the text area * * @param borderSpace * @since Envoy 0.2-alpha @@ -28,10 +29,10 @@ public class PrimaryTextArea extends JTextArea { public PrimaryTextArea(int borderSpace) { this(6, borderSpace); } /** - * Creates TextArea + * Creates the text area * * @param arcSize - * @param borderSpace + * @param borderSpace - the insets of the border on all four sides * @since Envoy 0.2-alpha */ public PrimaryTextArea(int arcSize, int borderSpace) { @@ -54,7 +55,7 @@ public class PrimaryTextArea extends JTextArea { } /** - * @return the arcSize + * @return the arcSize - the diameter of the arc at the four corners. * @since Envoy 0.2-alpha */ public int getArcSize() { return arcSize; } From 01d4c9eb13323d4e58f3a98906f79dc0f6cd2721 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 14 Dec 2019 13:52:47 +0100 Subject: [PATCH 109/474] Formatted --- src/main/java/envoy/client/LocalDB.java | 8 +- src/main/java/envoy/client/Settings.java | 10 +-- src/main/java/envoy/client/ui/ChatWindow.java | 40 +++------ .../envoy/client/ui/MessageListRenderer.java | 12 +-- .../java/envoy/client/ui/PrimaryTextArea.java | 9 +- .../java/envoy/client/ui/SettingsScreen.java | 87 ++++--------------- src/main/java/envoy/client/ui/Theme.java | 12 ++- .../envoy/client/ui/UserListRenderer.java | 19 ++-- 8 files changed, 58 insertions(+), 139 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index f061b28..5ca7a04 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -44,7 +44,7 @@ public class LocalDB { private Sync sync = objectFactory.createSync(); private Sync readMessages = objectFactory.createSync(); - private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); + private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); /** * Constructs an empty local database. @@ -134,13 +134,13 @@ public class LocalDB { return message; } - /** + /** * Creates a {@link Sync} object filled with the changes that occurred to the * local database since the last synchronization. * * @param userId the ID of the user that is synchronized by this client * @return {@link Sync} object filled with the current changes - * @since Envoy v0.1-alpha + * @since Envoy v0.1-alpha */ public Sync fillSync(long userId) { addWaitingMessagesToSync(); @@ -156,7 +156,7 @@ public class LocalDB { * Applies the changes carried by a {@link Sync} object to the local database * * @param returnSync the {@link Sync} object to apply - * @since Envoy v0.1-alpha + * @since Envoy v0.1-alpha */ public void applySync(Sync returnSync) { for (int i = 0; i < returnSync.getMessages().size(); i++) { diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 91f696f..fe5d769 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -73,9 +73,9 @@ public class Settings { // Load themes from theme file try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) { Object obj = in.readObject(); - if(obj instanceof HashMap) themes = (Map) obj; + if (obj instanceof HashMap) themes = (Map) obj; } catch (IOException | ClassNotFoundException e) { - themes = new HashMap<>(); + themes = new HashMap<>(); currentTheme = "dark"; e.printStackTrace(); } @@ -95,15 +95,15 @@ public class Settings { * @throws IOException * @since Envoy v0.2-alpha */ - public void save() throws IOException{ + public void save() throws IOException { prefs.put("username", getUsername()); prefs.put("email", getEmail()); prefs.put("theme", currentTheme); prefs.putBoolean("enterToSend", isEnterToSend()); - + // Save themes to theme file themeFile.createNewFile(); - try(ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) { + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) { out.writeObject(themes); } } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 1434148..ade7bcd 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -53,15 +53,15 @@ public class ChatWindow extends JFrame { private Client client; private LocalDB localDB; // GUI components - private JPanel contentPane = new JPanel(); - private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); - private JList userList = new JList<>(); + private JPanel contentPane = new JPanel(); + private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); + private JList userList = new JList<>(); private Chat currentChat; - private JList messageList = new JList<>(); - private JScrollPane scrollPane = new JScrollPane(); - private JTextPane textPane = new JTextPane(); + private JList messageList = new JList<>(); + private JScrollPane scrollPane = new JScrollPane(); + private JTextPane textPane = new JTextPane(); // private JCheckBox jCbChangeMode; - private PrimaryButton postButton = new PrimaryButton("Post"); + private PrimaryButton postButton = new PrimaryButton("Post"); private PrimaryButton settingsButton = new PrimaryButton("Settings"); private static int space = 4; @@ -76,8 +76,7 @@ public class ChatWindow extends JFrame { setBounds(100, 100, 600, 800); setTitle("Envoy"); setLocationRelativeTo(null); - setIconImage( - Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); + setIconImage(Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); // Save chats when window closes addWindowListener(new WindowAdapter() { @@ -131,8 +130,7 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER - && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) - || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); } } @@ -201,11 +199,7 @@ public class ChatWindow extends JFrame { final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = localDB.getChats() - .stream() - .filter(chat -> chat.getRecipient().getID() == user.getID()) - .findFirst() - .get(); + currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); // Set all unread messages in the chat to read readCurrentChat(); @@ -280,18 +274,14 @@ public class ChatWindow extends JFrame { private void postMessage(JList messageList) { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, - "Please select a recipient!", - "Cannot send message", - JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); return; } if (!messageEnterTextArea.getText().isEmpty()) try { // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), - currentChat.getRecipient().getID()); + final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient().getID()); currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); @@ -341,8 +331,7 @@ public class ChatWindow extends JFrame { new Thread(() -> { // Synchronize - localDB.applySync( - client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); // Process unread messages localDB.addUnreadMessagesToLocalDB(); @@ -352,8 +341,7 @@ public class ChatWindow extends JFrame { readCurrentChat(); // Update UI - SwingUtilities - .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); + SwingUtilities.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); }).start(); }).start(); } diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 2e6b65f..9be79c5 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -42,22 +42,18 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer

%s

%s :%s", + setText(String.format("

%s

%s :%s", dateColor, date, textColor, diff --git a/src/main/java/envoy/client/ui/PrimaryTextArea.java b/src/main/java/envoy/client/ui/PrimaryTextArea.java index e4d6fa1..1fd5584 100644 --- a/src/main/java/envoy/client/ui/PrimaryTextArea.java +++ b/src/main/java/envoy/client/ui/PrimaryTextArea.java @@ -16,9 +16,8 @@ import javax.swing.border.EmptyBorder; */ public class PrimaryTextArea extends JTextArea { - private static final long serialVersionUID = 1L; - - private int arcSize; + private static final long serialVersionUID = -5829028696155434913L; + private int arcSize; /** * Creates the text area @@ -31,8 +30,8 @@ public class PrimaryTextArea extends JTextArea { /** * Creates the text area * - * @param arcSize - * @param borderSpace - the insets of the border on all four sides + * @param arcSize is the diameter of the arc at the four corners. + * @param borderSpace is the insets of the border on all four sides. * @since Envoy 0.2-alpha */ public PrimaryTextArea(int arcSize, int borderSpace) { diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index bd80c2e..1f57199 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -101,8 +101,7 @@ public class SettingsScreen extends JDialog { createNewThemeButton.setEnabled(false); - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); // Content pane GridBagLayout gbl_contentPanel = new GridBagLayout(); @@ -200,20 +199,8 @@ public class SettingsScreen extends JDialog { colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getBackgroundColor(), - "Background", - 1); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getCellColor(), - "Cells", - 2); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getBackgroundColor(), "Background", 1); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getCellColor(), "Cells", 2); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), @@ -228,41 +215,11 @@ public class SettingsScreen extends JDialog { theme.getInteractableBackgroundColor(), "Interactable Background", 4); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getMessageColorChat(), - "Messages Chat", - 5); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getDateColorChat(), - "Date Chat", - 6); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getSelectionColor(), - "Selection", - 7); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getTypingMessageColor(), - "Typing Message", - 8); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getUserNameColor(), - "User Names", - 9); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getMessageColorChat(), "Messages Chat", 5); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getDateColorChat(), "Date Chat", 6); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getSelectionColor(), "Selection", 7); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getTypingMessageColor(), "Typing Message", 8); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getUserNameColor(), "User Names", 9); GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; @@ -283,16 +240,14 @@ public class SettingsScreen extends JDialog { String s = JOptionPane.showInputDialog("Enter a name for the new theme"); System.out.println(s); Settings.getInstance() - .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), - temporaryTheme.getCellColor(), temporaryTheme.getInteractableForegroundColor(), - temporaryTheme.getInteractableBackgroundColor(), temporaryTheme.getMessageColorChat(), - temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), + .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(), + temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(), + temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor())); themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName(); - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); createNewThemeButton.setEnabled(false); themes.addItem(themeArray[themeArray.length - 1]); @@ -412,21 +367,12 @@ public class SettingsScreen extends JDialog { temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getInteractableForegroundColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getInteractableBackgroundColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableForegroundColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getSelectionColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getTypingMessageColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getTypingMessageColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); colorsPanel.removeAll(); @@ -513,8 +459,7 @@ public class SettingsScreen extends JDialog { private void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); } - private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, - String name, int yIndex) { + private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, String name, int yIndex) { textPane.setFont(new Font("Arial", Font.PLAIN, 14)); textPane.setBackground(theme.getBackgroundColor()); textPane.setForeground(theme.getUserNameColor()); diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index a0ef259..7de0ea9 100644 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -26,9 +26,8 @@ public class Theme implements Serializable { private Color selectionColor; private Color typingMessageColor; - public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, - Color interactableBackgroundColor, Color messageColorChat, Color dateColorChat, Color selectionColor, - Color typingMessageColor, Color userNameColor) { + public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, Color interactableBackgroundColor, + Color messageColorChat, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) { this.themeName = themeName; @@ -42,11 +41,10 @@ public class Theme implements Serializable { this.typingMessageColor = typingMessageColor; this.userNameColor = userNameColor; } - + public Theme(String name, Theme other) { - this(name, other.backgroundColor, other.cellColor, other.interactableBackgroundColor, - other.interactableForegroundColor, other.messageColorChat, other.dateColorChat, other.selectionColor, - other.typingMessageColor, other.userNameColor); + this(name, other.backgroundColor, other.cellColor, other.interactableBackgroundColor, other.interactableForegroundColor, + other.messageColorChat, other.dateColorChat, other.selectionColor, other.typingMessageColor, other.userNameColor); } /** diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index c730e74..b145f28 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -44,23 +44,16 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { final UserStatus status = value.getStatus(); // Getting the UserNameColor of the current theme - String textColor = null; - textColor = toHex( - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); + String textColor = null; + textColor = toHex(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); switch (status) { case ONLINE: - setText(String.format( - "

%s

%s", - status, - textColor, - name)); + setText(String + .format("

%s

%s", status, textColor, name)); break; case OFFLINE: - setText(String.format( - "

%s

%s", - status, - textColor, - name)); + setText(String + .format("

%s

%s", status, textColor, name)); break; } return this; From 62635b9cfa6efa1034021a5e9442fb42f9e38c49 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 14 Dec 2019 14:17:24 +0100 Subject: [PATCH 110/474] Added background execution --- src/main/java/envoy/client/ui/Startup.java | 6 +++++- src/main/java/envoy/client/ui/StatusTrayIcon.java | 11 +++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 933890d..53cbbc0 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.JFrame; import javax.swing.JOptionPane; import envoy.client.Client; @@ -84,7 +85,7 @@ public class Startup { throw new EnvoyException("Could not enter offline mode: user name unknown"); client.setSender(clientUser); } catch(Exception e2) { - JOptionPane.showMessageDialog(null, e1.toString(), "Client error", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, e2.toString(), "Client error", JOptionPane.ERROR_MESSAGE); System.exit(1); return; } @@ -118,6 +119,9 @@ public class Startup { try { new StatusTrayIcon(chatWindow).show(); + + // If the tray icon is supported, hide the chat window on close + chatWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); } catch (EnvoyException e) { logger.warning("The StatusTrayIcon is not supported on this platform!"); } diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 01cc8d7..03380c2 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -75,16 +75,15 @@ public class StatusTrayIcon implements EventHandler { focusTarget.addWindowFocusListener(new WindowAdapter() { @Override - public void windowGainedFocus(WindowEvent e) { - displayMessages = false; - } + public void windowGainedFocus(WindowEvent e) { displayMessages = false; } @Override - public void windowLostFocus(WindowEvent e) { - displayMessages = true; - } + public void windowLostFocus(WindowEvent e) { displayMessages = true; } }); + // Show the window if the user clicks on the icon + trayIcon.addActionListener((evt) -> { focusTarget.setVisible(true); focusTarget.requestFocus(); }); + // Start processing message events EventBus.getInstance().register(this); } From cac42e2d838b623c5060768bbd9f6f40335a199b Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 14 Dec 2019 14:58:07 +0100 Subject: [PATCH 111/474] Implemented a (not working) own version of a logger and reformatted code --- src/main/java/envoy/client/Client.java | 21 +-- src/main/java/envoy/client/Config.java | 6 +- src/main/java/envoy/client/LocalDB.java | 3 +- src/main/java/envoy/client/Settings.java | 10 +- .../java/envoy/client/event/EnvoyLogger.java | 103 +++++++++++++ src/main/java/envoy/client/event/Event.java | 1 + src/main/java/envoy/client/ui/ChatWindow.java | 32 ++-- .../envoy/client/ui/MessageListRenderer.java | 12 +- .../java/envoy/client/ui/SettingsScreen.java | 145 +++++------------- src/main/java/envoy/client/ui/Startup.java | 3 +- .../java/envoy/client/ui/StatusTrayIcon.java | 8 +- src/main/java/envoy/client/ui/Theme.java | 12 +- .../envoy/client/ui/UserListRenderer.java | 24 +-- 13 files changed, 189 insertions(+), 191 deletions(-) create mode 100644 src/main/java/envoy/client/event/EnvoyLogger.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 8f96739..bd1555a 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,7 +1,5 @@ package envoy.client; -import java.util.logging.Logger; - import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; @@ -10,6 +8,7 @@ import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; +import envoy.client.event.EnvoyLogger; import envoy.schema.ObjectFactory; import envoy.schema.Sync; import envoy.schema.User; @@ -30,7 +29,7 @@ public class Client { private Config config; private User sender, recipient; - private static final Logger logger = Logger.getLogger(Client.class.getSimpleName()); + private static final EnvoyLogger logger = new EnvoyLogger(Client.class.getSimpleName()); public Client(Config config, String username) { this.config = config; @@ -63,9 +62,7 @@ public class Client { user.setID(-1); sendSync.getUsers().add(user); - Sync returnSendSync = post( - String - .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + Sync returnSendSync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), sendSync, Sync.class); return returnSendSync; @@ -85,9 +82,7 @@ public class Client { user.setName(name); senderSync.getUsers().add(user); - Sync returnSenderSync = post( - String - .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + Sync returnSenderSync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), senderSync, Sync.class); @@ -134,7 +129,8 @@ public class Client { * their updated UserStatus to the client.)
* * @param userId the id of the {@link Client} who sends the {@link Sync} - * @param sync the sync object (yet to be converted from java class to sync.xml) + * @param sync the sync object (yet to be converted from java class to + * sync.xml) * @return a returnSync.xml file * @since Envoy v0.1-alpha */ @@ -151,10 +147,7 @@ public class Client { } // Send sync - return post(String - .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), - sync, - Sync.class); + return post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), sync, Sync.class); } /** diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index bbd3b72..e9f2a18 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -71,9 +71,7 @@ public class Config { * @return {@code true} if server, port and localDB directory are known. * @since Envoy v0.1-alpha */ - public boolean isInitialized() { - return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; - } + public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; } /** * @return the host name of the Envoy server @@ -114,7 +112,7 @@ public class Config { /** * Changes the default local database. * Exclusively intended for development purposes. - * + * * @param localDB the file containing the local database * @since Envoy v0.1-alpha **/ diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index f061b28..51e2eb1 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -14,6 +14,7 @@ import java.util.logging.Logger; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; +import envoy.client.event.EnvoyLogger; import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; import envoy.exception.EnvoyException; @@ -44,7 +45,7 @@ public class LocalDB { private Sync sync = objectFactory.createSync(); private Sync readMessages = objectFactory.createSync(); - private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); + private static final Logger logger = new EnvoyLogger(LocalDB.class.getSimpleName()); /** * Constructs an empty local database. diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 91f696f..fe5d769 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -73,9 +73,9 @@ public class Settings { // Load themes from theme file try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) { Object obj = in.readObject(); - if(obj instanceof HashMap) themes = (Map) obj; + if (obj instanceof HashMap) themes = (Map) obj; } catch (IOException | ClassNotFoundException e) { - themes = new HashMap<>(); + themes = new HashMap<>(); currentTheme = "dark"; e.printStackTrace(); } @@ -95,15 +95,15 @@ public class Settings { * @throws IOException * @since Envoy v0.2-alpha */ - public void save() throws IOException{ + public void save() throws IOException { prefs.put("username", getUsername()); prefs.put("email", getEmail()); prefs.put("theme", currentTheme); prefs.putBoolean("enterToSend", isEnterToSend()); - + // Save themes to theme file themeFile.createNewFile(); - try(ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) { + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) { out.writeObject(themes); } } diff --git a/src/main/java/envoy/client/event/EnvoyLogger.java b/src/main/java/envoy/client/event/EnvoyLogger.java new file mode 100644 index 0000000..33e17ac --- /dev/null +++ b/src/main/java/envoy/client/event/EnvoyLogger.java @@ -0,0 +1,103 @@ +package envoy.client.event; + +import java.io.IOException; +import java.util.logging.ConsoleHandler; +import java.util.logging.FileHandler; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + +/** + * Project: envoy-client
+ * File: EnvoyLogger.java
+ * Created: 14 Dec 2019
+ * + * @author Leon Hofmeister + * @since Envoy v0.2-alpha + */ +public class EnvoyLogger extends Logger { + + private Logger logger; + private int fileLevel = 800; + + private Handler handler = new Handler() { + + @Override + public void publish(LogRecord arg0) { + ConsoleHandler ch; + FileHandler fh; + SimpleFormatter formatter = new SimpleFormatter(); + if (arg0.getLevel().intValue() >= fileLevel) {// Case if level >= info + try { + fh = new FileHandler("Envoy_user.log"); + logger.addHandler(fh); + formatter.formatMessage(arg0); + fh.setFormatter(formatter); + } catch (SecurityException | IOException e) { + e.printStackTrace(); + } + } + ch = new ConsoleHandler(); + logger.addHandler(ch); + formatter.formatMessage(arg0); + } + + @Override + public void flush() {} + + @Override + public void close() throws SecurityException {} + }; + + public EnvoyLogger(String name) { + super(name, null); + logger.addHandler(handler); + } + + /** + * Logs a message. If the problem severity is above the FileLevel-barrier, then + * the log entry will be written to a file. Regardless of problem severity, + * everything will be printed to the console. + * + * @param level the problem severity + * @param msg the message to be written in the log + * @since Envoy v0.2-alpha + */ + @Override + public void log(Level level, String msg) { + LogRecord lr = new LogRecord(level, msg); + logger.log(lr); + } + + /** + * Logs a message. If the problem severity is above the {@code FileLevel} + * barrier, then the log entry will be written to a file. + * Regardless of problem severity, everything will be printed to the console. + * + * @param logRecord the LogRecord (Level and String) to be treated by the + * Logger. + * @since Envoy v0.2-alpha + */ + @Override + public void log(LogRecord logRecord) { logger.log(logRecord); } + + /** + * @return the fileLevel: The current barrier for writing logs to a file. It can + * range from 100-1000 in steps of one hundred with 1000 being + * Level.SEVERE + * @since Envoy v0.2-alpha + */ + public int getFileLevel() { return fileLevel; } + + /** + * @param fileLevel the severity above which on logRecords will be written in a + * file instead of the console + * @since Envoy v0.2-alpha + */ + public void setFileLevel(int fileLevel) { + if (fileLevel <= 10) fileLevel *= 100; + this.fileLevel = fileLevel; + } +} diff --git a/src/main/java/envoy/client/event/Event.java b/src/main/java/envoy/client/event/Event.java index 9db2477..36e0466 100644 --- a/src/main/java/envoy/client/event/Event.java +++ b/src/main/java/envoy/client/event/Event.java @@ -6,6 +6,7 @@ package envoy.client.event; * Created: 04.12.2019
* * @author Kai S. K. Engelbart + * @param the type of our Event * @since Envoy v0.2-alpha */ public interface Event { diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 6867f5e..cafd790 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -12,7 +12,6 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -33,6 +32,7 @@ import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; import envoy.client.Settings; +import envoy.client.event.EnvoyLogger; import envoy.schema.Message; import envoy.schema.Sync; import envoy.schema.User; @@ -68,7 +68,7 @@ public class ChatWindow extends JFrame { private static int space = 4; - private static final Logger logger = Logger.getLogger(ChatWindow.class.getSimpleName()); + private static final EnvoyLogger logger = new EnvoyLogger(ChatWindow.class.getSimpleName()); public ChatWindow(Client client, LocalDB localDB) { this.client = client; @@ -132,8 +132,7 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER - && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) - || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); } } @@ -180,10 +179,9 @@ public class ChatWindow extends JFrame { settingsButton.addActionListener((evt) -> { try { - SettingsScreen.open(); - changeChatWindowColors(Settings.getInstance().getCurrentTheme()); - } catch (Exception e) { - SettingsScreen.open(); + new SettingsScreen().setVisible(true); + changeChatWindowColors(Settings.getInstance().getCurrentTheme()); + } catch (Exception e) { logger.log(Level.WARNING, "An error occured while opening the settings screen", e); e.printStackTrace(); } @@ -235,7 +233,7 @@ public class ChatWindow extends JFrame { gbc_userList.insets = new Insets(space, space, space, space); changeChatWindowColors(Settings.getInstance().getCurrentTheme()); - + contentPane.add(userList, gbc_userList); contentPane.revalidate(); @@ -244,7 +242,6 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); } - /** * Used to immediately reload the ChatWindow when settings were changed. @@ -287,18 +284,14 @@ public class ChatWindow extends JFrame { private void postMessage(JList messageList) { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, - "Please select a recipient!", - "Cannot send message", - JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); return; } if (!messageEnterTextArea.getText().isEmpty()) try { // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), - currentChat.getRecipient().getID()); + final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient().getID()); currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); @@ -348,8 +341,7 @@ public class ChatWindow extends JFrame { new Thread(() -> { // Synchronize - localDB.applySync( - client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); // Process unread messages localDB.addUnreadMessagesToLocalDB(); @@ -359,8 +351,7 @@ public class ChatWindow extends JFrame { readCurrentChat(); // Update UI - SwingUtilities - .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); + SwingUtilities.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); }).start(); }).start(); } @@ -377,4 +368,3 @@ public class ChatWindow extends JFrame { */ private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } } - diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 2e6b65f..9be79c5 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -42,22 +42,18 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer

%s

%s :%s", + setText(String.format("

%s

%s :%s", dateColor, date, textColor, diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index bd80c2e..c9fea6c 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -11,6 +11,7 @@ import java.awt.Insets; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Arrays; +import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.BoxLayout; @@ -25,8 +26,8 @@ import javax.swing.JPanel; import javax.swing.JTextPane; import javax.swing.ListSelectionModel; -import envoy.client.LocalDB; import envoy.client.Settings; +import envoy.client.event.EnvoyLogger; /** * This class provides the GUI to change the user specific settings. @@ -54,45 +55,28 @@ public class SettingsScreen extends JDialog { private GridBagConstraints gbc_themeContent = new GridBagConstraints(); - private Theme selectedTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + private JButton createNewThemeButton = new JButton("Create New Theme"); + private JPanel colorsPanel = new JPanel(); + private JButton okButton = new JButton("Save"); + private JButton cancelButton = new JButton("Cancel"); - private JButton createNewThemeButton = new JButton("Create New Theme"); - - private JPanel colorsPanel = new JPanel(); - private JButton okButton = new JButton("Save"); - private JButton cancelButton = new JButton("Cancel"); private static int space = 5; + private Theme selectedTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + private Theme temporaryTheme; - private boolean colorChanged = false; - private Theme temporaryTheme; - - private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); - - private static SettingsScreen settingsScreen; + private static final Logger logger = new EnvoyLogger(SettingsScreen.class.getSimpleName()); // TODO: Add a JPanel with all the Information necessary: // change (Picture,Username, Email, Password) and toggle(light/dark mode, // "ctrl+enter"/"enter" // to send a message directly) - /** - * Opens the settings screen.
- * - * @since Envoy v0.1-alpha - */ - public static void open() { - settingsScreen = new SettingsScreen(); - settingsScreen.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - settingsScreen.setModal(true); - settingsScreen.setVisible(true); - } - /** * Builds the settings screen. * * @since Envoy v0.1-alpha */ - private SettingsScreen() { + public SettingsScreen() { logger.info(Settings.getInstance().getCurrentTheme()); setBounds(10, 10, 450, 650); @@ -101,8 +85,7 @@ public class SettingsScreen extends JDialog { createNewThemeButton.setEnabled(false); - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); // Content pane GridBagLayout gbl_contentPanel = new GridBagLayout(); @@ -122,7 +105,7 @@ public class SettingsScreen extends JDialog { @SuppressWarnings("unchecked") final JList selectedOption = (JList) listSelectionEvent.getSource(); final String option = selectedOption.getSelectedValue(); - System.out.println(option); + logger.log(Level.FINEST, option); switch (option) { case "Color Themes": @@ -183,7 +166,7 @@ public class SettingsScreen extends JDialog { @Override public void itemStateChanged(ItemEvent e) { String selectedValue = (String) themes.getSelectedItem(); - System.out.println(selectedValue); + logger.log(Level.FINEST, selectedValue); selectedTheme = Settings.getInstance().getThemes().get(selectedValue); } }); @@ -200,20 +183,8 @@ public class SettingsScreen extends JDialog { colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getBackgroundColor(), - "Background", - 1); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getCellColor(), - "Cells", - 2); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getBackgroundColor(), "Background", 1); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getCellColor(), "Cells", 2); buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), @@ -228,41 +199,11 @@ public class SettingsScreen extends JDialog { theme.getInteractableBackgroundColor(), "Interactable Background", 4); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getMessageColorChat(), - "Messages Chat", - 5); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getDateColorChat(), - "Date Chat", - 6); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getSelectionColor(), - "Selection", - 7); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getTypingMessageColor(), - "Typing Message", - 8); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getUserNameColor(), - "User Names", - 9); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getMessageColorChat(), "Messages Chat", 5); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getDateColorChat(), "Date Chat", 6); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getSelectionColor(), "Selection", 7); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getTypingMessageColor(), "Typing Message", 8); + buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getUserNameColor(), "User Names", 9); GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; @@ -281,18 +222,16 @@ public class SettingsScreen extends JDialog { createNewThemeButton.addActionListener((evt) -> { try { String s = JOptionPane.showInputDialog("Enter a name for the new theme"); - System.out.println(s); + logger.log(Level.FINEST, s); Settings.getInstance() - .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), - temporaryTheme.getCellColor(), temporaryTheme.getInteractableForegroundColor(), - temporaryTheme.getInteractableBackgroundColor(), temporaryTheme.getMessageColorChat(), - temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), + .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(), + temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(), + temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor())); themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName(); - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); createNewThemeButton.setEnabled(false); themes.addItem(themeArray[themeArray.length - 1]); @@ -355,7 +294,7 @@ public class SettingsScreen extends JDialog { Settings.getInstance().setEnterToSend(Settings.getInstance().isEnterToSend());// still temporary Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); - System.out.println(selectedTheme.getThemeName()); + logger.log(Level.FINER, selectedTheme.getThemeName()); changeSettingsScreenColors(Settings.getInstance().getCurrentTheme()); updateColorVariables(Settings.getInstance().getCurrentTheme()); @@ -365,13 +304,17 @@ public class SettingsScreen extends JDialog { revalidate(); repaint(); } catch (Exception e) { - logger.info("Something went wrong when changing the setting"); - settingsScreen.dispose(); + logger.warning("Something went wrong when changing the setting"); + JOptionPane.showMessageDialog(this, "Something went wrong when changing the setting"); + dispose(); } }); } } changeSettingsScreenColors(Settings.getInstance().getCurrentTheme()); + + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + setModal(true); } private void changeSettingsScreenColors(String key) { @@ -412,21 +355,12 @@ public class SettingsScreen extends JDialog { temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getInteractableForegroundColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getInteractableBackgroundColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableForegroundColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getSelectionColor(), - Settings.getInstance() - .getThemes() - .get(Settings.getInstance().getCurrentTheme()) - .getTypingMessageColor(), + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getTypingMessageColor(), Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); colorsPanel.removeAll(); @@ -513,8 +447,7 @@ public class SettingsScreen extends JDialog { private void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); } - private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, - String name, int yIndex) { + private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, String name, int yIndex) { textPane.setFont(new Font("Arial", Font.PLAIN, 14)); textPane.setBackground(theme.getBackgroundColor()); textPane.setForeground(theme.getUserNameColor()); @@ -528,15 +461,11 @@ public class SettingsScreen extends JDialog { try { Color newColor = JColorChooser.showDialog(null, "Choose a color", color); if (newColor.getRGB() != color.getRGB()) { - System.out.println("New Color"); - System.out.println(color.getRGB()); - // TODO: When Theme changed in same settings screen, color variable doesnt - // update. + logger.log(Level.FINEST, String.valueOf(color.getRGB())); Color[] colorsArray = temporaryTheme.getAllColors(); for (int i = 0; i < colorsArray.length; i++) { if (color.getRGB() == colorsArray[i].getRGB()) { temporaryTheme.setColor(i, newColor); - colorChanged = true; createNewThemeButton.setEnabled(true); break; } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index edd5aa2..33e5c78 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -12,6 +12,7 @@ import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; import envoy.client.Settings; +import envoy.client.event.EnvoyLogger; import envoy.exception.EnvoyException; /** @@ -28,7 +29,7 @@ import envoy.exception.EnvoyException; */ public class Startup { - private static final Logger logger = Logger.getLogger(Startup.class.getSimpleName()); + private static final Logger logger = new EnvoyLogger(Startup.class.getSimpleName()); public static void main(String[] args) { logger.setLevel(Level.ALL); diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 01cc8d7..fee9a7c 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -75,14 +75,10 @@ public class StatusTrayIcon implements EventHandler { focusTarget.addWindowFocusListener(new WindowAdapter() { @Override - public void windowGainedFocus(WindowEvent e) { - displayMessages = false; - } + public void windowGainedFocus(WindowEvent e) { displayMessages = false; } @Override - public void windowLostFocus(WindowEvent e) { - displayMessages = true; - } + public void windowLostFocus(WindowEvent e) { displayMessages = true; } }); // Start processing message events diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index a0ef259..7de0ea9 100644 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -26,9 +26,8 @@ public class Theme implements Serializable { private Color selectionColor; private Color typingMessageColor; - public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, - Color interactableBackgroundColor, Color messageColorChat, Color dateColorChat, Color selectionColor, - Color typingMessageColor, Color userNameColor) { + public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, Color interactableBackgroundColor, + Color messageColorChat, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) { this.themeName = themeName; @@ -42,11 +41,10 @@ public class Theme implements Serializable { this.typingMessageColor = typingMessageColor; this.userNameColor = userNameColor; } - + public Theme(String name, Theme other) { - this(name, other.backgroundColor, other.cellColor, other.interactableBackgroundColor, - other.interactableForegroundColor, other.messageColorChat, other.dateColorChat, other.selectionColor, - other.typingMessageColor, other.userNameColor); + this(name, other.backgroundColor, other.cellColor, other.interactableBackgroundColor, other.interactableForegroundColor, + other.messageColorChat, other.dateColorChat, other.selectionColor, other.typingMessageColor, other.userNameColor); } /** diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index c730e74..1ee3f84 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -12,8 +12,8 @@ import envoy.schema.User; import envoy.schema.User.UserStatus; /** - * Defines how the {@code UserList} is displayed. - * + * Defines how the {@code UserList} is displayed.
+ *
* Project: envoy-client
* File: UserListRenderer.java
* Created: 12 Oct 2019
@@ -26,7 +26,6 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { private static final long serialVersionUID = 5164417379767181198L; - @SuppressWarnings("incomplete-switch") @Override public Component getListCellRendererComponent(JList list, User value, int index, boolean isSelected, boolean cellHasFocus) { if (isSelected) { @@ -44,23 +43,16 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { final UserStatus status = value.getStatus(); // Getting the UserNameColor of the current theme - String textColor = null; - textColor = toHex( - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); + String textColor = null; + textColor = toHex(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); switch (status) { case ONLINE: - setText(String.format( - "

%s

%s", - status, - textColor, - name)); + setText(String + .format("

%s

%s", status, textColor, name)); break; case OFFLINE: - setText(String.format( - "

%s

%s", - status, - textColor, - name)); + setText(String + .format("

%s

%s", status, textColor, name)); break; } return this; From c5956ef6f464717daa54683f2dec3f10cdda5a19 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 14 Dec 2019 19:10:45 +0100 Subject: [PATCH 112/474] Custom scroll bar * Added PrimaryScrollBar class * Implemented PrimaryScrollBar in ChatWindow for the ScrollPanes vertical scroll bar --- src/main/java/envoy/client/ui/ChatWindow.java | 11 +++ .../envoy/client/ui/PrimaryScrollBar.java | 95 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 src/main/java/envoy/client/ui/PrimaryScrollBar.java diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 1c562b6..a6510ec 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,5 +1,6 @@ package envoy.client.ui; +import java.awt.Color; import java.awt.ComponentOrientation; import java.awt.Font; import java.awt.GridBagConstraints; @@ -252,6 +253,16 @@ public class ChatWindow extends JFrame { // scrollPane scrollPane.setForeground(theme.getBackgroundColor()); scrollPane.setBackground(theme.getCellColor()); + // scrollPane.getVerticalScrollBar() + // .setBackground( + // new Color(theme.getBackgroundColor().getRed() + 50, + // theme.getBackgroundColor().getGreen() + 50, + // theme.getBackgroundColor().getBlue() + 50)); + scrollPane.getVerticalScrollBar().setBackground(theme.getCellColor()); + scrollPane.getVerticalScrollBar() + .setUI(new PrimaryScrollBar(5, theme.getInteractableBackgroundColor(), + new Color(theme.getInteractableBackgroundColor().getRGB() - 50), + new Color(theme.getInteractableBackgroundColor().getRGB() + 170))); // messageEnterTextArea messageEnterTextArea.setCaretColor(theme.getTypingMessageColor()); messageEnterTextArea.setForeground(theme.getTypingMessageColor()); diff --git a/src/main/java/envoy/client/ui/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/PrimaryScrollBar.java new file mode 100644 index 0000000..aaaa0a0 --- /dev/null +++ b/src/main/java/envoy/client/ui/PrimaryScrollBar.java @@ -0,0 +1,95 @@ +package envoy.client.ui; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.plaf.basic.BasicScrollBarUI; + +import envoy.client.Settings; + +/** + * Project: envoy-client
+ * File: PrimaryScrollBar.javaEvent.java
+ * Created: 14.12.2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.2-alpha + */ +public class PrimaryScrollBar extends BasicScrollBarUI{ + + private final Dimension d = new Dimension(); + private int arcSize; + private Color scrollBarColor; + private Color hoverColor; + private Color draggingColor; + + public PrimaryScrollBar(int arcSize, Color scrollBarColor, Color hoverColor, Color draggingColor) { + this.arcSize = arcSize; + this.scrollBarColor = scrollBarColor; + this.hoverColor = hoverColor; + this.draggingColor = draggingColor; + } + + @Override + protected JButton createDecreaseButton(int orientation) { + return new JButton() { + private static final long serialVersionUID = 1032443171070235890L; + + @Override + public Dimension getPreferredSize() { + return d; + } + }; + } + + @Override + protected JButton createIncreaseButton (int orientation) { + return new JButton() { + + private static final long serialVersionUID = 7575774542623215803L; + + @Override + public Dimension getPreferredSize() { + return d; + } + }; + } + @Override + protected void paintTrack(Graphics g, JComponent c, Rectangle r) { + } + + @Override + protected void paintThumb(Graphics g, JComponent c, Rectangle r) { + Graphics2D g2 = (Graphics2D) g.create(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Color color = null; + JScrollBar sb = (JScrollBar) c; + if (!sb.isEnabled() || r.width > r.height) { + return; + } else if (isDragging) { + color = draggingColor; + } else if (isThumbRollover()) { + color = hoverColor; + } else { + color = scrollBarColor; + } + g2.setPaint(color); + g2.fillRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); + g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); + g2.drawRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); + g2.dispose(); + } + + @Override + protected void setThumbBounds(int x, int y, int width, int height) { + super.setThumbBounds(x, y, width, height); + scrollbar.repaint(); + } +} From b1f9172b6366696b37c44f95e1c047336d8735d7 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sun, 15 Dec 2019 00:34:44 +0100 Subject: [PATCH 113/474] Horizontal Scroll Bar Implemented primaryScrollBar support for horizontal scroll bar as well. --- src/main/java/envoy/client/ui/ChatWindow.java | 10 ++++++- .../envoy/client/ui/PrimaryScrollBar.java | 26 ++++++++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index a6510ec..6968f5c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -262,7 +262,15 @@ public class ChatWindow extends JFrame { scrollPane.getVerticalScrollBar() .setUI(new PrimaryScrollBar(5, theme.getInteractableBackgroundColor(), new Color(theme.getInteractableBackgroundColor().getRGB() - 50), - new Color(theme.getInteractableBackgroundColor().getRGB() + 170))); + new Color(theme.getInteractableBackgroundColor().getRGB() + 170), true)); + scrollPane.getHorizontalScrollBar().setBackground(theme.getCellColor()); + scrollPane.getHorizontalScrollBar() + .setUI(new PrimaryScrollBar(5, theme.getInteractableBackgroundColor(), new Color(theme.getInteractableBackgroundColor().getRGB() - 50), + new Color(theme.getInteractableBackgroundColor().getRGB() + 170), false)); + // int currentVerticalScrollBarValue = + // scrollPane.getVerticalScrollBar().getValue() + + // scrollPane.getVerticalScrollBar().getVisibleAmount(); Work in Progress for + // autoscroll // messageEnterTextArea messageEnterTextArea.setCaretColor(theme.getTypingMessageColor()); messageEnterTextArea.setForeground(theme.getTypingMessageColor()); diff --git a/src/main/java/envoy/client/ui/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/PrimaryScrollBar.java index aaaa0a0..546119b 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollBar.java @@ -29,12 +29,14 @@ public class PrimaryScrollBar extends BasicScrollBarUI{ private Color scrollBarColor; private Color hoverColor; private Color draggingColor; + private boolean isVertical; - public PrimaryScrollBar(int arcSize, Color scrollBarColor, Color hoverColor, Color draggingColor) { + public PrimaryScrollBar(int arcSize, Color scrollBarColor, Color hoverColor, Color draggingColor, boolean isVertical) { this.arcSize = arcSize; this.scrollBarColor = scrollBarColor; this.hoverColor = hoverColor; this.draggingColor = draggingColor; + this.isVertical = isVertical; } @Override @@ -71,7 +73,7 @@ public class PrimaryScrollBar extends BasicScrollBarUI{ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Color color = null; JScrollBar sb = (JScrollBar) c; - if (!sb.isEnabled() || r.width > r.height) { + if (!sb.isEnabled() || (isVertical == true && r.width > r.height) || (isVertical == false && r.width < r.height)) { return; } else if (isDragging) { color = draggingColor; @@ -80,11 +82,21 @@ public class PrimaryScrollBar extends BasicScrollBarUI{ } else { color = scrollBarColor; } - g2.setPaint(color); - g2.fillRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); - g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); - g2.drawRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); - g2.dispose(); + + if (isVertical == true) { + g2.setPaint(color); + g2.fillRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); + g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); + g2.drawRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); + g2.dispose(); + } + if (isVertical == false) { + g2.setPaint(color); + g2.fillRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); + g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); + g2.drawRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); + g2.dispose(); + } } @Override From cda5c37a4a4463a8abc4e5035dd0a734e597f188 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sun, 15 Dec 2019 12:48:40 +0100 Subject: [PATCH 114/474] Autoscroll * Implemented functionality to automatically scroll down when user is on the bottom of the chat and then there are new messages added. * When chat is opened, the vertical scroll bar starts at the bottom. * When rereading messages, the chat doesn't scroll down if new messages are added. (Besides see first point) --- src/main/java/envoy/client/ui/ChatWindow.java | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 6968f5c..134734f 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -63,6 +63,8 @@ public class ChatWindow extends JFrame { // private JCheckBox jCbChangeMode; private PrimaryButton postButton = new PrimaryButton("Post"); private PrimaryButton settingsButton = new PrimaryButton("Settings"); + private int verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum(); + private boolean chatOpened = false; private static int space = 4; @@ -208,6 +210,7 @@ public class ChatWindow extends JFrame { textPane.setText(currentChat.getRecipient().getName()); messageList.setModel(currentChat.getModel()); + chatOpened = true; contentPane.revalidate(); } }); @@ -253,11 +256,8 @@ public class ChatWindow extends JFrame { // scrollPane scrollPane.setForeground(theme.getBackgroundColor()); scrollPane.setBackground(theme.getCellColor()); - // scrollPane.getVerticalScrollBar() - // .setBackground( - // new Color(theme.getBackgroundColor().getRed() + 50, - // theme.getBackgroundColor().getGreen() + 50, - // theme.getBackgroundColor().getBlue() + 50)); + + // Scroll Bar Styling scrollPane.getVerticalScrollBar().setBackground(theme.getCellColor()); scrollPane.getVerticalScrollBar() .setUI(new PrimaryScrollBar(5, theme.getInteractableBackgroundColor(), @@ -267,10 +267,26 @@ public class ChatWindow extends JFrame { scrollPane.getHorizontalScrollBar() .setUI(new PrimaryScrollBar(5, theme.getInteractableBackgroundColor(), new Color(theme.getInteractableBackgroundColor().getRGB() - 50), new Color(theme.getInteractableBackgroundColor().getRGB() + 170), false)); - // int currentVerticalScrollBarValue = - // scrollPane.getVerticalScrollBar().getValue() + - // scrollPane.getVerticalScrollBar().getVisibleAmount(); Work in Progress for - // autoscroll + + // Autoscroll + scrollPane.getVerticalScrollBar().addAdjustmentListener(e -> { + if ((verticalScrollBarMaximumValue - e.getAdjustable().getMaximum()) == 0) { + return; + } + + if (chatOpened == true) { + e.getAdjustable().setValue(e.getAdjustable().getMaximum()); + verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum(); + chatOpened = false; + return; + } + if (scrollPane.getVerticalScrollBar().getValue() + + scrollPane.getVerticalScrollBar().getVisibleAmount() + 100 >= scrollPane.getVerticalScrollBar().getMaximum()) { + e.getAdjustable().setValue(e.getAdjustable().getMaximum()); + verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum(); + } + }); + // messageEnterTextArea messageEnterTextArea.setCaretColor(theme.getTypingMessageColor()); messageEnterTextArea.setForeground(theme.getTypingMessageColor()); From cf56b2f7ade11b765e2b2b87199fcb696003ded9 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sun, 15 Dec 2019 12:53:01 +0100 Subject: [PATCH 115/474] Cold style improvement Changed if query with isVertical in PrimaryScrollBar to short form. --- src/main/java/envoy/client/ui/PrimaryScrollBar.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/envoy/client/ui/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/PrimaryScrollBar.java index 546119b..a7dc073 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollBar.java @@ -83,14 +83,14 @@ public class PrimaryScrollBar extends BasicScrollBarUI{ color = scrollBarColor; } - if (isVertical == true) { + if (isVertical) { g2.setPaint(color); g2.fillRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); g2.drawRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); g2.dispose(); } - if (isVertical == false) { + if (!isVertical) { g2.setPaint(color); g2.fillRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); From b051ddb831e82c93c6337c2af2eec6a7021c9b53 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 15 Dec 2019 16:26:11 +0100 Subject: [PATCH 116/474] Improved code style and formatting --- src/main/java/envoy/client/ui/ChatWindow.java | 33 ++++---- .../envoy/client/ui/PrimaryScrollBar.java | 83 ++++++++----------- 2 files changed, 48 insertions(+), 68 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 134734f..2e263da 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -49,22 +49,22 @@ public class ChatWindow extends JFrame { private static final long serialVersionUID = 6865098428255463649L; - // user specific objects + // User specific objects private Client client; private LocalDB localDB; + // GUI components - private JPanel contentPane = new JPanel(); - private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); - private JList userList = new JList<>(); + private JPanel contentPane = new JPanel(); + private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); + private JList userList = new JList<>(); private Chat currentChat; - private JList messageList = new JList<>(); - private JScrollPane scrollPane = new JScrollPane(); - private JTextPane textPane = new JTextPane(); - // private JCheckBox jCbChangeMode; - private PrimaryButton postButton = new PrimaryButton("Post"); - private PrimaryButton settingsButton = new PrimaryButton("Settings"); + private JList messageList = new JList<>(); + private JScrollPane scrollPane = new JScrollPane(); private int verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum(); private boolean chatOpened = false; + private JTextPane textPane = new JTextPane(); + private PrimaryButton postButton = new PrimaryButton("Post"); + private PrimaryButton settingsButton = new PrimaryButton("Settings"); private static int space = 4; @@ -239,7 +239,7 @@ public class ChatWindow extends JFrame { /** * Used to immediately reload the ChatWindow when settings were changed. - * + * * @since Envoy v0.1-alpha */ public void changeChatWindowColors(String key) { @@ -260,8 +260,7 @@ public class ChatWindow extends JFrame { // Scroll Bar Styling scrollPane.getVerticalScrollBar().setBackground(theme.getCellColor()); scrollPane.getVerticalScrollBar() - .setUI(new PrimaryScrollBar(5, theme.getInteractableBackgroundColor(), - new Color(theme.getInteractableBackgroundColor().getRGB() - 50), + .setUI(new PrimaryScrollBar(5, theme.getInteractableBackgroundColor(), new Color(theme.getInteractableBackgroundColor().getRGB() - 50), new Color(theme.getInteractableBackgroundColor().getRGB() + 170), true)); scrollPane.getHorizontalScrollBar().setBackground(theme.getCellColor()); scrollPane.getHorizontalScrollBar() @@ -270,9 +269,7 @@ public class ChatWindow extends JFrame { // Autoscroll scrollPane.getVerticalScrollBar().addAdjustmentListener(e -> { - if ((verticalScrollBarMaximumValue - e.getAdjustable().getMaximum()) == 0) { - return; - } + if ((verticalScrollBarMaximumValue - e.getAdjustable().getMaximum()) == 0) { return; } if (chatOpened == true) { e.getAdjustable().setValue(e.getAdjustable().getMaximum()); @@ -280,8 +277,8 @@ public class ChatWindow extends JFrame { chatOpened = false; return; } - if (scrollPane.getVerticalScrollBar().getValue() - + scrollPane.getVerticalScrollBar().getVisibleAmount() + 100 >= scrollPane.getVerticalScrollBar().getMaximum()) { + if (scrollPane.getVerticalScrollBar().getValue() + scrollPane.getVerticalScrollBar().getVisibleAmount() + + 100 >= scrollPane.getVerticalScrollBar().getMaximum()) { e.getAdjustable().setValue(e.getAdjustable().getMaximum()); verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum(); } diff --git a/src/main/java/envoy/client/ui/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/PrimaryScrollBar.java index a7dc073..845448c 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollBar.java @@ -16,23 +16,23 @@ import envoy.client.Settings; /** * Project: envoy-client
- * File: PrimaryScrollBar.javaEvent.java
+ * File: PrimaryScrollBar.java
* Created: 14.12.2019
- * + * * @author Maximilian Käfer * @since Envoy v0.2-alpha */ -public class PrimaryScrollBar extends BasicScrollBarUI{ - +public class PrimaryScrollBar extends BasicScrollBarUI { + private final Dimension d = new Dimension(); - private int arcSize; - private Color scrollBarColor; - private Color hoverColor; - private Color draggingColor; - private boolean isVertical; - + private final int arcSize; + private final Color scrollBarColor; + private final Color hoverColor; + private final Color draggingColor; + private final boolean isVertical; + public PrimaryScrollBar(int arcSize, Color scrollBarColor, Color hoverColor, Color draggingColor, boolean isVertical) { - this.arcSize = arcSize; + this.arcSize = arcSize; this.scrollBarColor = scrollBarColor; this.hoverColor = hoverColor; this.draggingColor = draggingColor; @@ -41,62 +41,45 @@ public class PrimaryScrollBar extends BasicScrollBarUI{ @Override protected JButton createDecreaseButton(int orientation) { - return new JButton() { - private static final long serialVersionUID = 1032443171070235890L; - - @Override - public Dimension getPreferredSize() { - return d; - } - }; + JButton button = new JButton(); + button.setPreferredSize(d); + return button; } - + @Override - protected JButton createIncreaseButton (int orientation) { - return new JButton() { - - private static final long serialVersionUID = 7575774542623215803L; - - @Override - public Dimension getPreferredSize() { - return d; - } - }; + protected JButton createIncreaseButton(int orientation) { + JButton button = new JButton(); + button.setPreferredSize(d); + return button; } + @Override - protected void paintTrack(Graphics g, JComponent c, Rectangle r) { - } - + protected void paintTrack(Graphics g, JComponent c, Rectangle r) {} + @Override protected void paintThumb(Graphics g, JComponent c, Rectangle r) { Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - Color color = null; - JScrollBar sb = (JScrollBar) c; - if (!sb.isEnabled() || (isVertical == true && r.width > r.height) || (isVertical == false && r.width < r.height)) { - return; - } else if (isDragging) { - color = draggingColor; - } else if (isThumbRollover()) { - color = hoverColor; - } else { - color = scrollBarColor; - } + Color color; + JScrollBar sb = (JScrollBar) c; + if (!sb.isEnabled() || (isVertical && r.width > r.height) || (!isVertical && r.width < r.height)) return; + + if (isDragging) color = draggingColor; + else if (isThumbRollover()) color = hoverColor; + else color = scrollBarColor; + + g2.setPaint(color); if (isVertical) { - g2.setPaint(color); g2.fillRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); g2.drawRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); - g2.dispose(); - } - if (!isVertical) { - g2.setPaint(color); + } else { g2.fillRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); g2.drawRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); - g2.dispose(); } + g2.dispose(); } @Override From 2405d4a6ad8c8a484f407864d307b97fff3312f9 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 15 Dec 2019 17:44:13 +0100 Subject: [PATCH 117/474] Added PrimaryScrollPane class with default scroll pane UI settings --- src/main/java/envoy/client/ui/ChatWindow.java | 55 ++++--------------- .../envoy/client/ui/PrimaryScrollBar.java | 5 ++ .../envoy/client/ui/PrimaryScrollPane.java | 48 ++++++++++++++++ 3 files changed, 64 insertions(+), 44 deletions(-) create mode 100644 src/main/java/envoy/client/ui/PrimaryScrollPane.java diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 2e263da..3a28754 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,6 +1,5 @@ package envoy.client.ui; -import java.awt.Color; import java.awt.ComponentOrientation; import java.awt.Font; import java.awt.GridBagConstraints; @@ -20,7 +19,6 @@ import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; -import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; @@ -54,17 +52,15 @@ public class ChatWindow extends JFrame { private LocalDB localDB; // GUI components - private JPanel contentPane = new JPanel(); - private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); - private JList userList = new JList<>(); - private Chat currentChat; - private JList messageList = new JList<>(); - private JScrollPane scrollPane = new JScrollPane(); - private int verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum(); - private boolean chatOpened = false; - private JTextPane textPane = new JTextPane(); - private PrimaryButton postButton = new PrimaryButton("Post"); - private PrimaryButton settingsButton = new PrimaryButton("Settings"); + private JPanel contentPane = new JPanel(); + private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); + private JList userList = new JList<>(); + private Chat currentChat; + private JList messageList = new JList<>(); + private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); + private JTextPane textPane = new JTextPane(); + private PrimaryButton postButton = new PrimaryButton("Post"); + private PrimaryButton settingsButton = new PrimaryButton("Settings"); private static int space = 4; @@ -115,7 +111,6 @@ public class ChatWindow extends JFrame { messageList.setBorder(new EmptyBorder(space, space, space, space)); scrollPane.setViewportView(messageList); - scrollPane.setBorder(null); GridBagConstraints gbc_scrollPane = new GridBagConstraints(); gbc_scrollPane.fill = GridBagConstraints.BOTH; @@ -210,7 +205,7 @@ public class ChatWindow extends JFrame { textPane.setText(currentChat.getRecipient().getName()); messageList.setModel(currentChat.getModel()); - chatOpened = true; + scrollPane.setChatOpened(true); contentPane.revalidate(); } }); @@ -254,35 +249,7 @@ public class ChatWindow extends JFrame { messageList.setForeground(theme.getMessageColorChat()); messageList.setBackground(theme.getCellColor()); // scrollPane - scrollPane.setForeground(theme.getBackgroundColor()); - scrollPane.setBackground(theme.getCellColor()); - - // Scroll Bar Styling - scrollPane.getVerticalScrollBar().setBackground(theme.getCellColor()); - scrollPane.getVerticalScrollBar() - .setUI(new PrimaryScrollBar(5, theme.getInteractableBackgroundColor(), new Color(theme.getInteractableBackgroundColor().getRGB() - 50), - new Color(theme.getInteractableBackgroundColor().getRGB() + 170), true)); - scrollPane.getHorizontalScrollBar().setBackground(theme.getCellColor()); - scrollPane.getHorizontalScrollBar() - .setUI(new PrimaryScrollBar(5, theme.getInteractableBackgroundColor(), new Color(theme.getInteractableBackgroundColor().getRGB() - 50), - new Color(theme.getInteractableBackgroundColor().getRGB() + 170), false)); - - // Autoscroll - scrollPane.getVerticalScrollBar().addAdjustmentListener(e -> { - if ((verticalScrollBarMaximumValue - e.getAdjustable().getMaximum()) == 0) { return; } - - if (chatOpened == true) { - e.getAdjustable().setValue(e.getAdjustable().getMaximum()); - verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum(); - chatOpened = false; - return; - } - if (scrollPane.getVerticalScrollBar().getValue() + scrollPane.getVerticalScrollBar().getVisibleAmount() - + 100 >= scrollPane.getVerticalScrollBar().getMaximum()) { - e.getAdjustable().setValue(e.getAdjustable().getMaximum()); - verticalScrollBarMaximumValue = scrollPane.getVerticalScrollBar().getMaximum(); - } - }); + scrollPane.applyTheme(theme); // messageEnterTextArea messageEnterTextArea.setCaretColor(theme.getTypingMessageColor()); diff --git a/src/main/java/envoy/client/ui/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/PrimaryScrollBar.java index 845448c..6853d8f 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollBar.java @@ -39,6 +39,11 @@ public class PrimaryScrollBar extends BasicScrollBarUI { this.isVertical = isVertical; } + public PrimaryScrollBar(Theme theme, boolean isVertical) { + this(5, theme.getInteractableBackgroundColor(), new Color(theme.getInteractableBackgroundColor().getRGB() - 50), + new Color(theme.getInteractableBackgroundColor().getRGB() + 170), isVertical); + } + @Override protected JButton createDecreaseButton(int orientation) { JButton button = new JButton(); diff --git a/src/main/java/envoy/client/ui/PrimaryScrollPane.java b/src/main/java/envoy/client/ui/PrimaryScrollPane.java new file mode 100644 index 0000000..d4e0b28 --- /dev/null +++ b/src/main/java/envoy/client/ui/PrimaryScrollPane.java @@ -0,0 +1,48 @@ +package envoy.client.ui; + +import javax.swing.JScrollPane; + +/** + * Project: envoy-client
+ * File: PrimaryScrollPane.java
+ * Created: 15 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class PrimaryScrollPane extends JScrollPane { + + private static final long serialVersionUID = -4786837444056228439L; + + private int verticalScrollBarMaximum = getVerticalScrollBar().getMaximum(); + private boolean chatOpened = false; + + public PrimaryScrollPane() { setBorder(null); } + + public void applyTheme(Theme theme) { + setForeground(theme.getBackgroundColor()); + setBackground(theme.getCellColor()); + + getVerticalScrollBar().setBackground(theme.getCellColor()); + getVerticalScrollBar().setUI(new PrimaryScrollBar(theme, true)); + getHorizontalScrollBar().setBackground(theme.getCellColor()); + getHorizontalScrollBar().setUI(new PrimaryScrollBar(theme, false)); + + // Automatic scrolling to the bottom + getVerticalScrollBar().addAdjustmentListener(e -> { + if (verticalScrollBarMaximum == e.getAdjustable().getMaximum()) return; + + if (chatOpened) { + e.getAdjustable().setValue(e.getAdjustable().getMaximum()); + verticalScrollBarMaximum = getVerticalScrollBar().getMaximum(); + chatOpened = false; + return; + } + if (getVerticalScrollBar().getValue() + getVerticalScrollBar().getVisibleAmount() + 100 >= getVerticalScrollBar().getMaximum()) { + e.getAdjustable().setValue(e.getAdjustable().getMaximum()); + verticalScrollBarMaximum = getVerticalScrollBar().getMaximum(); + } + }); + } + + public void setChatOpened(boolean chatOpened) { this.chatOpened = chatOpened; } +} From 4d235c2cd97cb1ba9f67dc3dd11e3a10d4cca25e Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sun, 15 Dec 2019 20:18:43 +0100 Subject: [PATCH 118/474] Formatting * Split applyTheme method in applyTheme and autoscroll. * Added Javadoc --- src/main/java/envoy/client/ui/ChatWindow.java | 1 + .../envoy/client/ui/PrimaryScrollPane.java | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 3a28754..9595d43 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -250,6 +250,7 @@ public class ChatWindow extends JFrame { messageList.setBackground(theme.getCellColor()); // scrollPane scrollPane.applyTheme(theme); + scrollPane.autoscroll(); // messageEnterTextArea messageEnterTextArea.setCaretColor(theme.getTypingMessageColor()); diff --git a/src/main/java/envoy/client/ui/PrimaryScrollPane.java b/src/main/java/envoy/client/ui/PrimaryScrollPane.java index d4e0b28..904806a 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollPane.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollPane.java @@ -8,6 +8,7 @@ import javax.swing.JScrollPane; * Created: 15 Dec 2019
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer */ public class PrimaryScrollPane extends JScrollPane { @@ -18,6 +19,12 @@ public class PrimaryScrollPane extends JScrollPane { public PrimaryScrollPane() { setBorder(null); } + /** + * Styles the vertical and horizontal scroll bars. + * + * @param theme + * @since Envoy v0.2-alpha + */ public void applyTheme(Theme theme) { setForeground(theme.getBackgroundColor()); setBackground(theme.getCellColor()); @@ -26,7 +33,22 @@ public class PrimaryScrollPane extends JScrollPane { getVerticalScrollBar().setUI(new PrimaryScrollBar(theme, true)); getHorizontalScrollBar().setBackground(theme.getCellColor()); getHorizontalScrollBar().setUI(new PrimaryScrollBar(theme, false)); + } + /** + * Implements autoscroll functionality for the vertical scroll bar.
+ *
+ * Functionality to automatically scroll down when user views
+ * the bottom of the chat while there are new messages added.
+ *
+ * When chat is opened, the vertical scroll bar starts at the bottom.
+ *
+ * When rereading messages, the chat doesn't scroll down if new messages
+ * are added. (Besides see first point) + * + * @since Envoy v0.2-alpha + */ + public void autoscroll() { // Automatic scrolling to the bottom getVerticalScrollBar().addAdjustmentListener(e -> { if (verticalScrollBarMaximum == e.getAdjustable().getMaximum()) return; From 0cd0380c87ea1b30beade562736bf82fb6fee03c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 16 Dec 2019 09:41:21 +0100 Subject: [PATCH 119/474] Added ThemeChangeEvent, improved EventHandler declaration --- src/main/java/envoy/client/event/Event.java | 6 +-- .../java/envoy/client/event/EventBus.java | 40 +++++++++------ .../java/envoy/client/event/EventHandler.java | 11 +--- .../envoy/client/event/ThemeChangeEvent.java | 20 ++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 11 ++-- .../java/envoy/client/ui/SettingsScreen.java | 50 +++++++------------ .../java/envoy/client/ui/StatusTrayIcon.java | 38 ++------------ 7 files changed, 79 insertions(+), 97 deletions(-) create mode 100644 src/main/java/envoy/client/event/ThemeChangeEvent.java diff --git a/src/main/java/envoy/client/event/Event.java b/src/main/java/envoy/client/event/Event.java index 9db2477..4a3264d 100644 --- a/src/main/java/envoy/client/event/Event.java +++ b/src/main/java/envoy/client/event/Event.java @@ -1,10 +1,10 @@ package envoy.client.event; /** - * Project: envoy-clientChess
- * File: Event.javaEvent.java
+ * Project: envoy-client
+ * File: Event.java
* Created: 04.12.2019
- * + * * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha */ diff --git a/src/main/java/envoy/client/event/EventBus.java b/src/main/java/envoy/client/event/EventBus.java index f6da3f5..06b385f 100644 --- a/src/main/java/envoy/client/event/EventBus.java +++ b/src/main/java/envoy/client/event/EventBus.java @@ -1,8 +1,9 @@ package envoy.client.event; import java.util.ArrayList; -import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * This class handles events by allowing {@link EventHandler} object to register @@ -10,11 +11,12 @@ import java.util.List; * bus.
*
* The event bus is a singleton and can be used across the entire application to - * guarantee the propagation of events. + * guarantee the propagation of events.
+ * * Project: envoy-client
* File: EventBus.java
* Created: 04.12.2019
- * + * * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha */ @@ -22,9 +24,10 @@ public class EventBus { /** * Contains all {@link EventHandler} instances registered at this - * {@link EventBus}. + * {@link EventBus} as values mapped to by their supported {@link Event} + * classes. */ - private List handlers = new ArrayList<>(); + private Map>, List> handlers = new HashMap<>(); /** * The singleton instance of this {@link EventBus} that is used across the @@ -46,26 +49,33 @@ public class EventBus { public static EventBus getInstance() { return eventBus; } /** - * Registers a list of {@link EventHandler} objects to be notified when a - * {@link Event} is dispatched that they are subscribed to. - * - * @param handlers the {@link EventHandler} objects to register + * Registers an {@link EventHandler} to be notified when a + * {@link Event} of a certain type is dispatched. + * + * @param eventClass the class which the {@link EventHandler} is subscribed to + * @param handler the {@link EventHandler} to register * @since Envoy v0.2-alpha */ - public void register(EventHandler... handlers) { this.handlers.addAll(Arrays.asList(handlers)); } + public void register(Class> eventClass, EventHandler handler) { + if (!handlers.containsKey(eventClass)) handlers.put(eventClass, new ArrayList<>()); + handlers.get(eventClass).add(handler); + } /** * Dispatches a {@link Event} to every {@link EventHandler} subscribed to it. - * + * * @param event the {@link Event} to dispatch * @since Envoy v0.2-alpha */ - public void dispatch(Event event) { handlers.stream().filter(h -> h.supports().contains(event.getClass())).forEach(h -> h.handle(event)); } + public void dispatch(Event event) { + handlers.keySet().stream().filter(event.getClass()::isAssignableFrom).map(handlers::get).flatMap(List::stream).forEach(h -> h.handle(event)); + } /** - * @return a list of all {@link EventHandler} instances currently registered at - * this {@link EventBus} + * @return a map of all {@link EventHandler} instances currently registered at + * this {@link EventBus} with the {@link Event} classes they are + * subscribed to as keys * @since Envoy v0.2-alpha */ - public List getHandlers() { return handlers; } + public Map>, List> getHandlers() { return handlers; } } diff --git a/src/main/java/envoy/client/event/EventHandler.java b/src/main/java/envoy/client/event/EventHandler.java index a6e5b81..ef3daea 100644 --- a/src/main/java/envoy/client/event/EventHandler.java +++ b/src/main/java/envoy/client/event/EventHandler.java @@ -1,25 +1,18 @@ package envoy.client.event; -import java.util.Set; - /** * Project: envoy-clientChess
* File: EventHandler.javaEvent.java
* Created: 04.12.2019
- * + * * @author Kai S. K. Engelbart */ public interface EventHandler { /** * Consumes an event dispatched by the event bus. - * + * * @param event The event dispatched by the event bus, only of supported type */ void handle(Event event); - - /** - * @return A set of classes this class is supposed to handle in events - */ - Set>> supports(); } diff --git a/src/main/java/envoy/client/event/ThemeChangeEvent.java b/src/main/java/envoy/client/event/ThemeChangeEvent.java new file mode 100644 index 0000000..d3ba96b --- /dev/null +++ b/src/main/java/envoy/client/event/ThemeChangeEvent.java @@ -0,0 +1,20 @@ +package envoy.client.event; + +import envoy.client.ui.Theme; + +/** + * Project: envoy-client
+ * File: ThemeChangeEvent.java
+ * Created: 15 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class ThemeChangeEvent implements Event { + + private final Theme theme; + + public ThemeChangeEvent(Theme theme) { this.theme = theme; } + + @Override + public Theme get() { return theme; } +} diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 9595d43..49c73df 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -30,6 +30,8 @@ import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; import envoy.client.Settings; +import envoy.client.event.EventBus; +import envoy.client.event.ThemeChangeEvent; import envoy.schema.Message; import envoy.schema.User; @@ -166,7 +168,6 @@ public class ChatWindow extends JFrame { settingsButton.addActionListener((evt) -> { try { SettingsScreen.open(); - changeChatWindowColors(Settings.getInstance().getCurrentTheme()); } catch (Exception e) { SettingsScreen.open(); logger.log(Level.WARNING, "An error occured while opening the settings screen", e); @@ -220,11 +221,13 @@ public class ChatWindow extends JFrame { gbc_userList.anchor = GridBagConstraints.PAGE_START; gbc_userList.insets = new Insets(space, space, space, space); - changeChatWindowColors(Settings.getInstance().getCurrentTheme()); + changeChatWindowColors(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); contentPane.add(userList, gbc_userList); contentPane.revalidate(); + EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> changeChatWindowColors((Theme) evt.get())); + loadUsersAndChats(); if (client.isOnline()) startSyncThread(Config.getInstance().getSyncTimeout()); @@ -237,9 +240,7 @@ public class ChatWindow extends JFrame { * * @since Envoy v0.1-alpha */ - public void changeChatWindowColors(String key) { - Theme theme = Settings.getInstance().getThemes().get(key); - + private void changeChatWindowColors(Theme theme) { // contentPane contentPane.setBackground(theme.getBackgroundColor()); contentPane.setForeground(theme.getUserNameColor()); diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index 161365d..fc0ebda 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -27,14 +27,16 @@ import javax.swing.ListSelectionModel; import envoy.client.LocalDB; import envoy.client.Settings; +import envoy.client.event.EventBus; +import envoy.client.event.ThemeChangeEvent; /** * This class provides the GUI to change the user specific settings. - * + * * Project: envoy-client
* File: SettingsScreen.java
* Created: 31 Oct 2019
- * + * * @author Leon Hofmeister * @author Maximilian Käfer * @author Kai S. K. Engelbart @@ -45,12 +47,12 @@ public class SettingsScreen extends JDialog { private final JPanel contentPanel = new JPanel(); private DefaultListModel optionsListModel = new DefaultListModel<>(); - private final JList options = new JList(); + private final JList options = new JList<>(); private JPanel buttonPane = new JPanel(); private JPanel themeContent = new JPanel(); private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]); - private JComboBox themes = new JComboBox(themeArray); + private JComboBox themes = new JComboBox<>(themeArray); private GridBagConstraints gbc_themeContent = new GridBagConstraints(); @@ -63,8 +65,7 @@ public class SettingsScreen extends JDialog { private JButton cancelButton = new JButton("Cancel"); private static int space = 5; - private boolean colorChanged = false; - private Theme temporaryTheme; + private Theme temporaryTheme; private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); @@ -77,7 +78,7 @@ public class SettingsScreen extends JDialog { /** * Opens the settings screen.
- * + * * @since Envoy v0.1-alpha */ public static void open() { @@ -89,7 +90,7 @@ public class SettingsScreen extends JDialog { /** * Builds the settings screen. - * + * * @since Envoy v0.1-alpha */ private SettingsScreen() { @@ -296,9 +297,10 @@ public class SettingsScreen extends JDialog { Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); System.out.println(selectedTheme.getThemeName()); - changeSettingsScreenColors(Settings.getInstance().getCurrentTheme()); - updateColorVariables(Settings.getInstance().getCurrentTheme()); - + final Theme currentTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + changeSettingsScreenColors(currentTheme); + updateColorVariables(currentTheme); + EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); Settings.getInstance().save(); revalidate(); @@ -310,11 +312,10 @@ public class SettingsScreen extends JDialog { }); } } - changeSettingsScreenColors(Settings.getInstance().getCurrentTheme()); + changeSettingsScreenColors(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); } - private void changeSettingsScreenColors(String key) { - Theme theme = Settings.getInstance().getThemes().get(key); + private void changeSettingsScreenColors(Theme theme) { // whole JDialog setBackground(theme.getBackgroundColor()); // contentPanel @@ -345,19 +346,8 @@ public class SettingsScreen extends JDialog { } - private void updateColorVariables(String key) { - Theme theme = Settings.getInstance().getThemes().get(key); - - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getBackgroundColor(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableForegroundColor(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getSelectionColor(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getTypingMessageColor(), - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); + private void updateColorVariables(Theme theme) { + temporaryTheme = new Theme("temporaryTheme", theme); colorsPanel.removeAll(); @@ -462,7 +452,6 @@ public class SettingsScreen extends JDialog { // TODO: When Theme changed in same settings screen, color variable doesnt // update. temporaryTheme.setColor(yIndex, newColor); - colorChanged = true; createNewThemeButton.setEnabled(true); } button.setBackground(newColor); @@ -481,8 +470,5 @@ public class SettingsScreen extends JDialog { colorsPanel.add(panel); } - private Color getInvertedColor(Color color) { - return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); - } - + private Color getInvertedColor(Color color) { return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); } } diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 03380c2..4670377 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -11,12 +11,8 @@ import java.awt.TrayIcon.MessageType; import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.util.HashSet; -import java.util.Set; -import envoy.client.event.Event; import envoy.client.event.EventBus; -import envoy.client.event.EventHandler; import envoy.client.event.MessageCreationEvent; import envoy.exception.EnvoyException; import envoy.schema.Message; @@ -29,7 +25,7 @@ import envoy.schema.Message; * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha */ -public class StatusTrayIcon implements EventHandler { +public class StatusTrayIcon { /** * The {@link TrayIcon} provided by the System Tray API for controlling the @@ -85,7 +81,10 @@ public class StatusTrayIcon implements EventHandler { trayIcon.addActionListener((evt) -> { focusTarget.setVisible(true); focusTarget.requestFocus(); }); // Start processing message events - EventBus.getInstance().register(this); + EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { + if (displayMessages) + trayIcon.displayMessage("New message received", ((MessageCreationEvent) evt).get().getContent().get(0).getText(), MessageType.INFO); + }); } /** @@ -102,31 +101,4 @@ public class StatusTrayIcon implements EventHandler { throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); } } - - /** - * Notifies the user of a message by displaying a pop-up every time a new - * message is received. - * - * @since Envoy v0.2-alpha - */ - @Override - public void handle(Event event) { - System.out.println("Message received. Displaying message: " + displayMessages); - if (displayMessages) - trayIcon.displayMessage("New message received", ((MessageCreationEvent) event).get().getContent().get(0).getText(), MessageType.INFO); - } - - /** - * The {@link StatusTrayIcon} only reacts to {@link MessageCreationEvent} - * instances which signify newly received messages. - * - * @return A set with the single element {@code MessageCreationEvent.class} - * @since Envoy v0.2-alpha - */ - @Override - public Set>> supports() { - Set>> supportedEvents = new HashSet<>(); - supportedEvents.add(MessageCreationEvent.class); - return supportedEvents; - } } From 7de411f7351f7251c52daeeaf2e43fe52be3a17f Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 17 Dec 2019 08:17:22 +0100 Subject: [PATCH 120/474] Fixed vertical scroll bar drawing on 4K monitors --- src/main/java/envoy/client/ui/ChatWindow.java | 1 - src/main/java/envoy/client/ui/PrimaryScrollBar.java | 6 +++--- src/main/java/envoy/client/ui/PrimaryScrollPane.java | 5 +++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 49c73df..910180c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -195,7 +195,6 @@ public class ChatWindow extends JFrame { @SuppressWarnings("unchecked") final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); - client.setRecipient(user); currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); diff --git a/src/main/java/envoy/client/ui/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/PrimaryScrollBar.java index 6853d8f..20bed6c 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollBar.java @@ -68,7 +68,7 @@ public class PrimaryScrollBar extends BasicScrollBarUI { Color color; JScrollBar sb = (JScrollBar) c; - if (!sb.isEnabled() || (isVertical && r.width > r.height) || (!isVertical && r.width < r.height)) return; + if (!sb.isEnabled()) return; if (isDragging) color = draggingColor; else if (isThumbRollover()) color = hoverColor; @@ -76,9 +76,9 @@ public class PrimaryScrollBar extends BasicScrollBarUI { g2.setPaint(color); if (isVertical) { - g2.fillRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); + g2.fillRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); - g2.drawRoundRect(r.x + 9, r.y, r.width - 10, r.height, arcSize, arcSize); + g2.drawRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); } else { g2.fillRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); diff --git a/src/main/java/envoy/client/ui/PrimaryScrollPane.java b/src/main/java/envoy/client/ui/PrimaryScrollPane.java index 904806a..61c348a 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollPane.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollPane.java @@ -21,7 +21,7 @@ public class PrimaryScrollPane extends JScrollPane { /** * Styles the vertical and horizontal scroll bars. - * + * * @param theme * @since Envoy v0.2-alpha */ @@ -31,6 +31,7 @@ public class PrimaryScrollPane extends JScrollPane { getVerticalScrollBar().setBackground(theme.getCellColor()); getVerticalScrollBar().setUI(new PrimaryScrollBar(theme, true)); + getHorizontalScrollBar().setBackground(theme.getCellColor()); getHorizontalScrollBar().setUI(new PrimaryScrollBar(theme, false)); } @@ -45,7 +46,7 @@ public class PrimaryScrollPane extends JScrollPane { *
* When rereading messages, the chat doesn't scroll down if new messages
* are added. (Besides see first point) - * + * * @since Envoy v0.2-alpha */ public void autoscroll() { From 3652a5bc9722be48c5eae67ae6a5ee411e385758 Mon Sep 17 00:00:00 2001 From: delvh Date: Wed, 18 Dec 2019 17:11:56 +0100 Subject: [PATCH 121/474] Updated EnvoyLogger -> still not working --- src/main/java/envoy/client/Settings.java | 16 ++--- .../java/envoy/client/event/EnvoyLogger.java | 64 +++++++------------ src/main/java/envoy/client/ui/ChatWindow.java | 6 +- 3 files changed, 33 insertions(+), 53 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index fe5d769..f078d2d 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -92,7 +92,7 @@ public class Settings { /** * updates prefs when save button is clicked * - * @throws IOException + * @throws IOException if saving was not successful * @since Envoy v0.2-alpha */ public void save() throws IOException { @@ -111,7 +111,7 @@ public class Settings { /** * adds new theme to the theme map and sets current theme to the new theme. * - * @param theme + * @param theme the theme to add * @since Envoy v0.2-alpha */ public void addNewThemeToMap(Theme theme) { @@ -120,7 +120,7 @@ public class Settings { } /** - * @return {@link currentTheme} + * @return the name of the current theme * @since Envoy v0.2-alpha */ public String getCurrentTheme() { return currentTheme; } @@ -128,7 +128,7 @@ public class Settings { /** * Sets the currentTheme * - * @param themeName + * @param themeName the name of the new current theme * @since Envoy v0.2-alpha */ public void setCurrentTheme(String themeName) { currentTheme = themeName; } @@ -174,16 +174,16 @@ public class Settings { public void setEnterToSend(boolean enterToSend) { this.enterToSend = enterToSend; } /** - * @return {@link themes} map + * @return the map of all themes by name and colorContent * @since Envoy v0.2-alpha */ public Map getThemes() { return themes; } /** - * Sets {@link themes} + * @deprecated not used * - * @param themes + * @param themes the the the the * @since Envoy v0.2-alpha */ - public void setThemes(Map themes) { this.themes = themes; } + public void setThemes(Map themes) { this.themes = themes; }// TODO delete, if there is no usage } \ No newline at end of file diff --git a/src/main/java/envoy/client/event/EnvoyLogger.java b/src/main/java/envoy/client/event/EnvoyLogger.java index 33e17ac..cbc2c88 100644 --- a/src/main/java/envoy/client/event/EnvoyLogger.java +++ b/src/main/java/envoy/client/event/EnvoyLogger.java @@ -3,7 +3,6 @@ package envoy.client.event; import java.io.IOException; import java.util.logging.ConsoleHandler; import java.util.logging.FileHandler; -import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; @@ -20,40 +19,24 @@ import java.util.logging.SimpleFormatter; public class EnvoyLogger extends Logger { private Logger logger; - private int fileLevel = 800; - - private Handler handler = new Handler() { - - @Override - public void publish(LogRecord arg0) { - ConsoleHandler ch; - FileHandler fh; - SimpleFormatter formatter = new SimpleFormatter(); - if (arg0.getLevel().intValue() >= fileLevel) {// Case if level >= info - try { - fh = new FileHandler("Envoy_user.log"); - logger.addHandler(fh); - formatter.formatMessage(arg0); - fh.setFormatter(formatter); - } catch (SecurityException | IOException e) { - e.printStackTrace(); - } - } - ch = new ConsoleHandler(); - logger.addHandler(ch); - formatter.formatMessage(arg0); - } - - @Override - public void flush() {} - - @Override - public void close() throws SecurityException {} - }; + private Level fileLevelBarrier = Level.CONFIG; public EnvoyLogger(String name) { super(name, null); - logger.addHandler(handler); + try { + SimpleFormatter formatter = new SimpleFormatter(); + FileHandler fh = new FileHandler("envoy_user.log"); + fh.setLevel(fileLevelBarrier); + fh.setFormatter(formatter); + ConsoleHandler ch = new ConsoleHandler(); + ch.setLevel(Level.FINEST); + ch.setFormatter(formatter); + logger.addHandler(fh); + logger.addHandler(ch); + } catch (IOException | SecurityException e) { + e.printStackTrace(); + this.log(Level.FINE, "Ironically, the logger encountered an error while initialising. That certainly needs to be logged :)"); + } } /** @@ -84,20 +67,17 @@ public class EnvoyLogger extends Logger { public void log(LogRecord logRecord) { logger.log(logRecord); } /** - * @return the fileLevel: The current barrier for writing logs to a file. It can - * range from 100-1000 in steps of one hundred with 1000 being - * Level.SEVERE + * @return the fileLevelBarrier: The current barrier for writing logs to a file. * @since Envoy v0.2-alpha */ - public int getFileLevel() { return fileLevel; } + public Level getFileLevelBarrier() { return fileLevelBarrier; } /** - * @param fileLevel the severity above which on logRecords will be written in a - * file instead of the console + * @param fileLevelBarrier the severity below which logRecords will be written + * only to the console. At or above they'll also be + * logged in a file. Can be written either in Digits + * from 0 - 1000 or with the according name of the level * @since Envoy v0.2-alpha */ - public void setFileLevel(int fileLevel) { - if (fileLevel <= 10) fileLevel *= 100; - this.fileLevel = fileLevel; - } + public void setFileLevel(String fileLevelBarrier) { this.fileLevelBarrier = Level.parse(fileLevelBarrier); } } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index cafd790..8761b74 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -245,11 +245,11 @@ public class ChatWindow extends JFrame { /** * Used to immediately reload the ChatWindow when settings were changed. - * + * @param themeName the name of the theme to change the colors into * @since Envoy v0.1-alpha */ - public void changeChatWindowColors(String key) { - Theme theme = Settings.getInstance().getThemes().get(key); + public void changeChatWindowColors(String themeName) { + Theme theme = Settings.getInstance().getThemes().get(themeName); // contentPane contentPane.setBackground(theme.getBackgroundColor()); From 9b679aa049d24c14343e7fb8b8c9f7366cadb169 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 18 Dec 2019 22:07:05 +0100 Subject: [PATCH 122/474] Added Javadoc requested by @delvh --- .../java/envoy/client/ui/PrimaryButton.java | 10 +- .../envoy/client/ui/PrimaryScrollBar.java | 210 ++++++++++-------- .../envoy/client/ui/PrimaryScrollPane.java | 12 + 3 files changed, 132 insertions(+), 100 deletions(-) diff --git a/src/main/java/envoy/client/ui/PrimaryButton.java b/src/main/java/envoy/client/ui/PrimaryButton.java index fe93571..65c52a0 100644 --- a/src/main/java/envoy/client/ui/PrimaryButton.java +++ b/src/main/java/envoy/client/ui/PrimaryButton.java @@ -8,7 +8,7 @@ import javax.swing.JButton; * Project: envoy-client
* File: PrimaryButton.javaEvent.java
* Created: 07.12.2019
- * + * * @author Kai S. K. Engelbart * @author Maximilian Käfer * @since Envoy v0.2-alpha @@ -21,7 +21,7 @@ public class PrimaryButton extends JButton { /** * Creates a primary button - * + * * @param title the title of the button * @since Envoy 0.2-alpha */ @@ -29,9 +29,9 @@ public class PrimaryButton extends JButton { /** * Creates a primary button - * - * @param title the title of the button - * @param the size of the arc used to draw the round button edges + * + * @param title the title of the button + * @param arcSize the size of the arc used to draw the round button edges * @since Envoy 0.2-alpha */ public PrimaryButton(String title, int arcSize) { diff --git a/src/main/java/envoy/client/ui/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/PrimaryScrollBar.java index 20bed6c..a7cb8fc 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollBar.java @@ -1,95 +1,115 @@ -package envoy.client.ui; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.RenderingHints; - -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JScrollBar; -import javax.swing.plaf.basic.BasicScrollBarUI; - -import envoy.client.Settings; - -/** - * Project: envoy-client
- * File: PrimaryScrollBar.java
- * Created: 14.12.2019
- * - * @author Maximilian Käfer - * @since Envoy v0.2-alpha - */ -public class PrimaryScrollBar extends BasicScrollBarUI { - - private final Dimension d = new Dimension(); - private final int arcSize; - private final Color scrollBarColor; - private final Color hoverColor; - private final Color draggingColor; - private final boolean isVertical; - - public PrimaryScrollBar(int arcSize, Color scrollBarColor, Color hoverColor, Color draggingColor, boolean isVertical) { - this.arcSize = arcSize; - this.scrollBarColor = scrollBarColor; - this.hoverColor = hoverColor; - this.draggingColor = draggingColor; - this.isVertical = isVertical; - } - - public PrimaryScrollBar(Theme theme, boolean isVertical) { - this(5, theme.getInteractableBackgroundColor(), new Color(theme.getInteractableBackgroundColor().getRGB() - 50), - new Color(theme.getInteractableBackgroundColor().getRGB() + 170), isVertical); - } - - @Override - protected JButton createDecreaseButton(int orientation) { - JButton button = new JButton(); - button.setPreferredSize(d); - return button; - } - - @Override - protected JButton createIncreaseButton(int orientation) { - JButton button = new JButton(); - button.setPreferredSize(d); - return button; - } - - @Override - protected void paintTrack(Graphics g, JComponent c, Rectangle r) {} - - @Override - protected void paintThumb(Graphics g, JComponent c, Rectangle r) { - Graphics2D g2 = (Graphics2D) g.create(); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - Color color; - JScrollBar sb = (JScrollBar) c; - - if (!sb.isEnabled()) return; - - if (isDragging) color = draggingColor; - else if (isThumbRollover()) color = hoverColor; - else color = scrollBarColor; - - g2.setPaint(color); - if (isVertical) { - g2.fillRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); - g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); - g2.drawRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); - } else { - g2.fillRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); - g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); - g2.drawRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); - } - g2.dispose(); - } - - @Override - protected void setThumbBounds(int x, int y, int width, int height) { - super.setThumbBounds(x, y, width, height); - scrollbar.repaint(); - } -} +package envoy.client.ui; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.plaf.basic.BasicScrollBarUI; + +import envoy.client.Settings; + +/** + * Project: envoy-client
+ * File: PrimaryScrollBar.java
+ * Created: 14.12.2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.2-alpha + */ +public class PrimaryScrollBar extends BasicScrollBarUI { + + private final Dimension d = new Dimension(); + private final int arcSize; + private final Color scrollBarColor; + private final Color hoverColor; + private final Color draggingColor; + private final boolean isVertical; + + /** + * Initializes a {@link PrimaryScrollBar} with a color scheme. + * + * @param arcSize the size of the arc used to draw the round scroll bar + * edges + * @param scrollBarColor the default color + * @param hoverColor the color while hovering + * @param draggingColor the color while dragging + * @param isVertical indicates whether this is a vertical + * {@link PrimaryScrollBar} + */ + public PrimaryScrollBar(int arcSize, Color scrollBarColor, Color hoverColor, Color draggingColor, boolean isVertical) { + this.arcSize = arcSize; + this.scrollBarColor = scrollBarColor; + this.hoverColor = hoverColor; + this.draggingColor = draggingColor; + this.isVertical = isVertical; + } + + /** + * Initializes a {@link PrimaryScrollBar} using a color scheme specified in a + * {@link Theme} + * + * @param theme the {@link Theme} to be applied to this + * {@link PrimaryScrollBar} + * @param isVertical indicates whether this is a vertical + * {@link PrimaryScrollBar} + */ + public PrimaryScrollBar(Theme theme, boolean isVertical) { + this(5, theme.getInteractableBackgroundColor(), new Color(theme.getInteractableBackgroundColor().getRGB() - 50), + new Color(theme.getInteractableBackgroundColor().getRGB() + 170), isVertical); + } + + @Override + protected JButton createDecreaseButton(int orientation) { + JButton button = new JButton(); + button.setPreferredSize(d); + return button; + } + + @Override + protected JButton createIncreaseButton(int orientation) { + JButton button = new JButton(); + button.setPreferredSize(d); + return button; + } + + @Override + protected void paintTrack(Graphics g, JComponent c, Rectangle r) {} + + @Override + protected void paintThumb(Graphics g, JComponent c, Rectangle r) { + Graphics2D g2 = (Graphics2D) g.create(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Color color; + JScrollBar sb = (JScrollBar) c; + + if (!sb.isEnabled()) return; + + if (isDragging) color = draggingColor; + else if (isThumbRollover()) color = hoverColor; + else color = scrollBarColor; + + g2.setPaint(color); + if (isVertical) { + g2.fillRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); + g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); + g2.drawRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); + } else { + g2.fillRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); + g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); + g2.drawRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); + } + g2.dispose(); + } + + @Override + protected void setThumbBounds(int x, int y, int width, int height) { + super.setThumbBounds(x, y, width, height); + scrollbar.repaint(); + } +} diff --git a/src/main/java/envoy/client/ui/PrimaryScrollPane.java b/src/main/java/envoy/client/ui/PrimaryScrollPane.java index 61c348a..8b78a99 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollPane.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollPane.java @@ -17,6 +17,11 @@ public class PrimaryScrollPane extends JScrollPane { private int verticalScrollBarMaximum = getVerticalScrollBar().getMaximum(); private boolean chatOpened = false; + /** + * Initializes a {@link JScrollPane} with the primary Envoy design scheme + * + * @since Envoy v0.2-alpha + */ public PrimaryScrollPane() { setBorder(null); } /** @@ -67,5 +72,12 @@ public class PrimaryScrollPane extends JScrollPane { }); } + /** + * Indicates a chat being opened by the user to this {@link PrimaryScrollPane} + * triggering it to automatically scroll down. + * + * @param chatOpened indicates the chat opening status + * @since Envoy v0.2-alpha + */ public void setChatOpened(boolean chatOpened) { this.chatOpened = chatOpened; } } From 3a3d6fe6490ef1f5ed4607484371728af52c92e9 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 20 Dec 2019 11:31:12 +0100 Subject: [PATCH 123/474] Improved Javadoc slightly --- src/main/java/envoy/client/event/EnvoyLogger.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/envoy/client/event/EnvoyLogger.java b/src/main/java/envoy/client/event/EnvoyLogger.java index cbc2c88..da562a3 100644 --- a/src/main/java/envoy/client/event/EnvoyLogger.java +++ b/src/main/java/envoy/client/event/EnvoyLogger.java @@ -73,9 +73,9 @@ public class EnvoyLogger extends Logger { public Level getFileLevelBarrier() { return fileLevelBarrier; } /** - * @param fileLevelBarrier the severity below which logRecords will be written - * only to the console. At or above they'll also be - * logged in a file. Can be written either in Digits + * @param fileLevelBarrier the severity below which {@link LogRecord}s will be + * written only to the console. At or above they'll also + * be logged in a file. Can be written either in Digits * from 0 - 1000 or with the according name of the level * @since Envoy v0.2-alpha */ From 2685276ae3d065cd98b7bd0a98d9f4a1b40f9481 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Fri, 20 Dec 2019 11:59:11 +0100 Subject: [PATCH 124/474] Fixed Logger initialization Renamed EnvoyLogger to EnvoyLog and moved it to the newl< created envoy.client.util package. --- src/main/java/envoy/client/Client.java | 6 +- src/main/java/envoy/client/LocalDB.java | 4 +- .../java/envoy/client/event/EnvoyLogger.java | 83 ------------------- src/main/java/envoy/client/ui/ChatWindow.java | 5 +- .../java/envoy/client/ui/SettingsScreen.java | 4 +- src/main/java/envoy/client/ui/Startup.java | 7 +- src/main/java/envoy/client/util/EnvoyLog.java | 70 ++++++++++++++++ 7 files changed, 83 insertions(+), 96 deletions(-) delete mode 100644 src/main/java/envoy/client/event/EnvoyLogger.java create mode 100644 src/main/java/envoy/client/util/EnvoyLog.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index bd1555a..1a8ce34 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,5 +1,7 @@ package envoy.client; +import java.util.logging.Logger; + import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; @@ -8,7 +10,7 @@ import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; -import envoy.client.event.EnvoyLogger; +import envoy.client.util.EnvoyLog; import envoy.schema.ObjectFactory; import envoy.schema.Sync; import envoy.schema.User; @@ -29,7 +31,7 @@ public class Client { private Config config; private User sender, recipient; - private static final EnvoyLogger logger = new EnvoyLogger(Client.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); public Client(Config config, String username) { this.config = config; diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 51e2eb1..b09c808 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -14,9 +14,9 @@ import java.util.logging.Logger; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; -import envoy.client.event.EnvoyLogger; import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; +import envoy.client.util.EnvoyLog; import envoy.exception.EnvoyException; import envoy.schema.Message; import envoy.schema.Message.Metadata.MessageState; @@ -45,7 +45,7 @@ public class LocalDB { private Sync sync = objectFactory.createSync(); private Sync readMessages = objectFactory.createSync(); - private static final Logger logger = new EnvoyLogger(LocalDB.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(LocalDB.class.getSimpleName()); /** * Constructs an empty local database. diff --git a/src/main/java/envoy/client/event/EnvoyLogger.java b/src/main/java/envoy/client/event/EnvoyLogger.java deleted file mode 100644 index cbc2c88..0000000 --- a/src/main/java/envoy/client/event/EnvoyLogger.java +++ /dev/null @@ -1,83 +0,0 @@ -package envoy.client.event; - -import java.io.IOException; -import java.util.logging.ConsoleHandler; -import java.util.logging.FileHandler; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; -import java.util.logging.SimpleFormatter; - -/** - * Project: envoy-client
- * File: EnvoyLogger.java
- * Created: 14 Dec 2019
- * - * @author Leon Hofmeister - * @since Envoy v0.2-alpha - */ -public class EnvoyLogger extends Logger { - - private Logger logger; - private Level fileLevelBarrier = Level.CONFIG; - - public EnvoyLogger(String name) { - super(name, null); - try { - SimpleFormatter formatter = new SimpleFormatter(); - FileHandler fh = new FileHandler("envoy_user.log"); - fh.setLevel(fileLevelBarrier); - fh.setFormatter(formatter); - ConsoleHandler ch = new ConsoleHandler(); - ch.setLevel(Level.FINEST); - ch.setFormatter(formatter); - logger.addHandler(fh); - logger.addHandler(ch); - } catch (IOException | SecurityException e) { - e.printStackTrace(); - this.log(Level.FINE, "Ironically, the logger encountered an error while initialising. That certainly needs to be logged :)"); - } - } - - /** - * Logs a message. If the problem severity is above the FileLevel-barrier, then - * the log entry will be written to a file. Regardless of problem severity, - * everything will be printed to the console. - * - * @param level the problem severity - * @param msg the message to be written in the log - * @since Envoy v0.2-alpha - */ - @Override - public void log(Level level, String msg) { - LogRecord lr = new LogRecord(level, msg); - logger.log(lr); - } - - /** - * Logs a message. If the problem severity is above the {@code FileLevel} - * barrier, then the log entry will be written to a file. - * Regardless of problem severity, everything will be printed to the console. - * - * @param logRecord the LogRecord (Level and String) to be treated by the - * Logger. - * @since Envoy v0.2-alpha - */ - @Override - public void log(LogRecord logRecord) { logger.log(logRecord); } - - /** - * @return the fileLevelBarrier: The current barrier for writing logs to a file. - * @since Envoy v0.2-alpha - */ - public Level getFileLevelBarrier() { return fileLevelBarrier; } - - /** - * @param fileLevelBarrier the severity below which logRecords will be written - * only to the console. At or above they'll also be - * logged in a file. Can be written either in Digits - * from 0 - 1000 or with the according name of the level - * @since Envoy v0.2-alpha - */ - public void setFileLevel(String fileLevelBarrier) { this.fileLevelBarrier = Level.parse(fileLevelBarrier); } -} diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 8761b74..cbdd7f5 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -12,6 +12,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -32,7 +33,7 @@ import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; import envoy.client.Settings; -import envoy.client.event.EnvoyLogger; +import envoy.client.util.EnvoyLog; import envoy.schema.Message; import envoy.schema.Sync; import envoy.schema.User; @@ -68,7 +69,7 @@ public class ChatWindow extends JFrame { private static int space = 4; - private static final EnvoyLogger logger = new EnvoyLogger(ChatWindow.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class.getSimpleName()); public ChatWindow(Client client, LocalDB localDB) { this.client = client; diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index c9fea6c..490985a 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -27,7 +27,7 @@ import javax.swing.JTextPane; import javax.swing.ListSelectionModel; import envoy.client.Settings; -import envoy.client.event.EnvoyLogger; +import envoy.client.util.EnvoyLog; /** * This class provides the GUI to change the user specific settings. @@ -64,7 +64,7 @@ public class SettingsScreen extends JDialog { private Theme selectedTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); private Theme temporaryTheme; - private static final Logger logger = new EnvoyLogger(SettingsScreen.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(SettingsScreen.class.getSimpleName()); // TODO: Add a JPanel with all the Information necessary: // change (Picture,Username, Email, Password) and toggle(light/dark mode, diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 33e5c78..bbfedb6 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -3,7 +3,6 @@ package envoy.client.ui; import java.awt.EventQueue; import java.io.IOException; import java.util.Properties; -import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; @@ -12,7 +11,7 @@ import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; import envoy.client.Settings; -import envoy.client.event.EnvoyLogger; +import envoy.client.util.EnvoyLog; import envoy.exception.EnvoyException; /** @@ -29,11 +28,9 @@ import envoy.exception.EnvoyException; */ public class Startup { - private static final Logger logger = new EnvoyLogger(Startup.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(Startup.class.getSimpleName()); public static void main(String[] args) { - logger.setLevel(Level.ALL); - Config config = Config.getInstance(); // Load the configuration from client.properties first diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java new file mode 100644 index 0000000..db4e03c --- /dev/null +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -0,0 +1,70 @@ +package envoy.client.util; + +import java.io.File; +import java.io.IOException; +import java.util.logging.ConsoleHandler; +import java.util.logging.FileHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + +/** + * Project: envoy-client
+ * File: EnvoyLogger.java
+ * Created: 14 Dec 2019
+ * + * @author Leon Hofmeister + * @since Envoy v0.2-alpha + */ +public class EnvoyLog { + + private static Level fileLevelBarrier = Level.CONFIG; + + private EnvoyLog() {} + + /** + * Creates a {@link Logger} with a specified name + * @param name the name of the {@link Logger} to create + * @return the created {@link Logger} + */ + public static Logger getLogger(String name) { + // Get a logger with the specified name + Logger logger = Logger.getLogger(name); + + final String logPath = "log/envoy_user.log"; + new File(logPath).getParentFile().mkdirs(); + + SimpleFormatter formatter = new SimpleFormatter(); + + try { + FileHandler fh = new FileHandler(logPath); + fh.setLevel(fileLevelBarrier); + fh.setFormatter(formatter); + logger.addHandler(fh); + } catch (SecurityException | IOException e) { + e.printStackTrace(); + } + + ConsoleHandler ch = new ConsoleHandler(); + ch.setLevel(Level.FINEST); + ch.setFormatter(formatter); + logger.addHandler(ch); + + return logger; + } + + /** + * @return the fileLevelBarrier: The current barrier for writing logs to a file. + * @since Envoy v0.2-alpha + */ + public static Level getFileLevelBarrier() { return fileLevelBarrier; } + + /** + * @param fileLevelBarrier the severity below which logRecords will be written + * only to the console. At or above they'll also be + * logged in a file. Can be written either in Digits + * from 0 - 1000 or with the according name of the level + * @since Envoy v0.2-alpha + */ + public static void setFileLevel(String fileLevelBarrier) { EnvoyLog.fileLevelBarrier = Level.parse(fileLevelBarrier); } +} From 6f9b777da3ca7f24e34f29d80bae0540bf41d8d1 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Fri, 20 Dec 2019 12:01:09 +0100 Subject: [PATCH 125/474] Added log directory to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2b99822..d77958c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target/ /localDB/ -/themes.ser +/log/ +/themes.ser \ No newline at end of file From e77abd3b00387644e70f6e6301a30ddc1a8a8db4 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Fri, 20 Dec 2019 12:36:53 +0100 Subject: [PATCH 126/474] Fixed errors caused by preparing the merge into develop --- src/main/java/envoy/client/ui/ChatWindow.java | 2 +- .../java/envoy/client/ui/SettingsScreen.java | 9 +------- src/main/java/envoy/client/ui/Startup.java | 23 ++++++++----------- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 378c990..8814195 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -170,7 +170,7 @@ public class ChatWindow extends JFrame { settingsButton.addActionListener((evt) -> { try { new SettingsScreen().setVisible(true); - changeChatWindowColors(Settings.getInstance().getCurrentTheme()); + changeChatWindowColors(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); } catch (Exception e) { logger.log(Level.WARNING, "An error occured while opening the settings screen", e); e.printStackTrace(); diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java index d659beb..75ce884 100644 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/SettingsScreen.java @@ -64,17 +64,10 @@ public class SettingsScreen extends JDialog { private static int space = 5; - private Theme temporaryTheme; + private Theme temporaryTheme, selectedTheme; private static final Logger logger = EnvoyLog.getLogger(SettingsScreen.class.getSimpleName()); - private static SettingsScreen settingsScreen; - - // TODO: Add a JPanel with all the Information necessary: - // change (Picture,Username, Email, Password) and toggle(light/dark mode, - // "ctrl+enter"/"enter" - // to send a message directly) - /** * Builds the settings screen. * diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 9b69cd8..b9f9633 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -2,6 +2,7 @@ package envoy.client.ui; import java.awt.EventQueue; import java.io.IOException; +import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFrame; @@ -10,9 +11,7 @@ import javax.swing.JOptionPane; import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; -import envoy.client.Settings; import envoy.client.util.EnvoyLog; - import envoy.exception.EnvoyException; import envoy.schema.User; @@ -57,7 +56,7 @@ public class Startup { logger.severe("User name is not set or empty. Exiting..."); System.exit(1); } - + // Initialize the local database LocalDB localDB; try { @@ -81,19 +80,18 @@ public class Startup { // Try entering offline mode localDB.loadUsers(); User clientUser = localDB.getUsers().get(userName); - if(clientUser == null) - throw new EnvoyException("Could not enter offline mode: user name unknown"); + if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); client.setSender(clientUser); - } catch(Exception e2) { + } catch (Exception e2) { JOptionPane.showMessageDialog(null, e2.toString(), "Client error", JOptionPane.ERROR_MESSAGE); System.exit(1); return; } } - + // Set client user in local database localDB.setUser(client.getSender()); - + // Initialize chats in local database try { localDB.initializeDBFile(); @@ -105,13 +103,12 @@ public class Startup { "Local DB error", JOptionPane.WARNING_MESSAGE); } - + logger.info("Client user ID: " + client.getSender().getID()); // Save all users to the local database - if(client.isOnline()) - localDB.setUsers(client.getUsers()); - + if (client.isOnline()) localDB.setUsers(client.getUsers()); + EventQueue.invokeLater(() -> { try { ChatWindow chatWindow = new ChatWindow(client, localDB); @@ -119,7 +116,7 @@ public class Startup { try { new StatusTrayIcon(chatWindow).show(); - + // If the tray icon is supported, hide the chat window on close chatWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); } catch (EnvoyException e) { From c9c99b3117e1624c963d5f7fda335d04f9152d65 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 20 Dec 2019 12:51:35 +0100 Subject: [PATCH 127/474] Deleted an unnecessary comment as per @CyB3RC0nN0Rs request --- src/main/java/envoy/client/Settings.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 78472ef..fe49ced 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -150,10 +150,8 @@ public class Settings { public Map getThemes() { return themes; } /** - * @deprecated not used - * * @param themes the the the the * @since Envoy v0.2-alpha */ - public void setThemes(Map themes) { this.themes = themes; }// TODO delete, if there is no usage + public void setThemes(Map themes) { this.themes = themes; } } \ No newline at end of file From 549fc3de7a00ad1933569302a941dc0c850dc8a2 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 20 Dec 2019 12:53:40 +0100 Subject: [PATCH 128/474] Updated malformed Javadoc --- src/main/java/envoy/client/Client.java | 2 +- src/main/java/envoy/client/LocalDB.java | 3 +- src/main/java/envoy/client/Settings.java | 14 +- src/main/java/envoy/client/event/Event.java | 35 ++--- .../envoy/client/ui/PrimaryScrollPane.java | 2 +- .../java/envoy/client/ui/PrimaryTextArea.java | 134 +++++++++--------- .../envoy/client/ui/UserListRenderer.java | 1 - 7 files changed, 96 insertions(+), 95 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index b7cc83c..be0dd89 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -35,7 +35,7 @@ public class Client { /** * Initializes the client. At this state, the client user has yet to be - * initialized, which can be done by calling {@link Client#onlineInit(String). + * initialized, which can be done by calling {@link Client#onlineInit(String)}. * * @param config The {@link Config} instance to use in this client * @since Envoy v0.2-alpha diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 60de119..5fe62a3 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -52,9 +52,10 @@ public class LocalDB { /** * Constructs an empty local database. To serialize any chats to the file - * system, call {@link LocalDB#initializeDBFile(File)}. + * system, call {@link LocalDB#initializeDBFile()}. * * @param localDBDir the directory in which to store users and chats + * @throws IOException if the LocalDB could not be initialised * @since Envoy v0.1-alpha */ public LocalDB(File localDBDir) throws IOException { diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 6ac095e..f172816 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -88,7 +88,7 @@ public class Settings { /** * Updates the preferences when the save button is clicked. * - * @throws IOException + * @throws IOException if something went wrong while saving * @since Envoy v0.2-alpha */ public void save() throws IOException { @@ -105,7 +105,7 @@ public class Settings { /** * adds new theme to the theme map and sets current theme to the new theme. * - * @param theme + * @param theme the theme to add * @since Envoy v0.2-alpha */ public void addNewThemeToMap(Theme theme) { @@ -114,7 +114,7 @@ public class Settings { } /** - * @return {@link currentTheme} + * @return the name of the current Theme * @since Envoy v0.2-alpha */ public String getCurrentTheme() { return currentTheme; } @@ -122,7 +122,7 @@ public class Settings { /** * Sets the currentTheme * - * @param themeName + * @param themeName the name of the current theme * @since Envoy v0.2-alpha */ public void setCurrentTheme(String themeName) { currentTheme = themeName; } @@ -144,15 +144,15 @@ public class Settings { public void setEnterToSend(boolean enterToSend) { this.enterToSend = enterToSend; } /** - * @return {@link themes} map + * @return the map of all themes * @since Envoy v0.2-alpha */ public Map getThemes() { return themes; } /** - * Sets {@link themes} + * Sets the map of all themes * - * @param themes + * @param themes a map(String, Theme) of all themes * @since Envoy v0.2-alpha */ public void setThemes(Map themes) { this.themes = themes; } diff --git a/src/main/java/envoy/client/event/Event.java b/src/main/java/envoy/client/event/Event.java index 4a3264d..32009b9 100644 --- a/src/main/java/envoy/client/event/Event.java +++ b/src/main/java/envoy/client/event/Event.java @@ -1,17 +1,18 @@ -package envoy.client.event; - -/** - * Project: envoy-client
- * File: Event.java
- * Created: 04.12.2019
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha - */ -public interface Event { - - /** - * @return the data associated with this event - */ - T get(); -} +package envoy.client.event; + +/** + * Project: envoy-client
+ * File: Event.java
+ * Created: 04.12.2019
+ * + * @author Kai S. K. Engelbart + * @param the type of the Event + * @since Envoy v0.2-alpha + */ +public interface Event { + + /** + * @return the data associated with this event + */ + T get(); +} diff --git a/src/main/java/envoy/client/ui/PrimaryScrollPane.java b/src/main/java/envoy/client/ui/PrimaryScrollPane.java index 8b78a99..f8e4dbc 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollPane.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollPane.java @@ -27,7 +27,7 @@ public class PrimaryScrollPane extends JScrollPane { /** * Styles the vertical and horizontal scroll bars. * - * @param theme + * @param theme the color set used to color the component * @since Envoy v0.2-alpha */ public void applyTheme(Theme theme) { diff --git a/src/main/java/envoy/client/ui/PrimaryTextArea.java b/src/main/java/envoy/client/ui/PrimaryTextArea.java index 1fd5584..29ed2f9 100644 --- a/src/main/java/envoy/client/ui/PrimaryTextArea.java +++ b/src/main/java/envoy/client/ui/PrimaryTextArea.java @@ -1,67 +1,67 @@ -package envoy.client.ui; - -import java.awt.Font; -import java.awt.Graphics; - -import javax.swing.JTextArea; -import javax.swing.border.EmptyBorder; - -/** - * Project: envoy-client
- * File: PrimaryTextArea.javaEvent.java
- * Created: 07.12.2019
- * - * @author Maximilian Käfer - * @since Envoy v0.2-alpha - */ -public class PrimaryTextArea extends JTextArea { - - private static final long serialVersionUID = -5829028696155434913L; - private int arcSize; - - /** - * Creates the text area - * - * @param borderSpace - * @since Envoy 0.2-alpha - */ - public PrimaryTextArea(int borderSpace) { this(6, borderSpace); } - - /** - * Creates the text area - * - * @param arcSize is the diameter of the arc at the four corners. - * @param borderSpace is the insets of the border on all four sides. - * @since Envoy 0.2-alpha - */ - public PrimaryTextArea(int arcSize, int borderSpace) { - super(); - setWrapStyleWord(true); - setLineWrap(true); - setBorder(null); - setFont(new Font("Arial", Font.PLAIN, 17)); - setBorder(new EmptyBorder(borderSpace, borderSpace, borderSpace, borderSpace)); - setOpaque(false); - - this.arcSize = arcSize; - } - - @Override - protected void paintComponent(Graphics g) { - g.setColor(getBackground()); - g.fillRoundRect(0, 0, getWidth(), getHeight(), arcSize, arcSize); - super.paintComponent(g); - } - - /** - * @return the arcSize - the diameter of the arc at the four corners. - * @since Envoy 0.2-alpha - */ - public int getArcSize() { return arcSize; } - - /** - * @param arcSize the arcSize to set - * @since Envoy 0.2-alpha - */ - public void setArcSize(int arcSize) { this.arcSize = arcSize; } -} +package envoy.client.ui; + +import java.awt.Font; +import java.awt.Graphics; + +import javax.swing.JTextArea; +import javax.swing.border.EmptyBorder; + +/** + * Project: envoy-client
+ * File: PrimaryTextArea.javaEvent.java
+ * Created: 07.12.2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.2-alpha + */ +public class PrimaryTextArea extends JTextArea { + + private static final long serialVersionUID = -5829028696155434913L; + private int arcSize; + + /** + * Creates the text area + * + * @param borderSpace the space between components + * @since Envoy 0.2-alpha + */ + public PrimaryTextArea(int borderSpace) { this(6, borderSpace); } + + /** + * Creates the text area + * + * @param arcSize is the diameter of the arc at the four corners. + * @param borderSpace is the insets of the border on all four sides. + * @since Envoy 0.2-alpha + */ + public PrimaryTextArea(int arcSize, int borderSpace) { + super(); + setWrapStyleWord(true); + setLineWrap(true); + setBorder(null); + setFont(new Font("Arial", Font.PLAIN, 17)); + setBorder(new EmptyBorder(borderSpace, borderSpace, borderSpace, borderSpace)); + setOpaque(false); + + this.arcSize = arcSize; + } + + @Override + protected void paintComponent(Graphics g) { + g.setColor(getBackground()); + g.fillRoundRect(0, 0, getWidth(), getHeight(), arcSize, arcSize); + super.paintComponent(g); + } + + /** + * @return the arcSize - the diameter of the arc at the four corners. + * @since Envoy 0.2-alpha + */ + public int getArcSize() { return arcSize; } + + /** + * @param arcSize the arcSize to set + * @since Envoy 0.2-alpha + */ + public void setArcSize(int arcSize) { this.arcSize = arcSize; } +} diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index b145f28..c3c7ef2 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -26,7 +26,6 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { private static final long serialVersionUID = 5164417379767181198L; - @SuppressWarnings("incomplete-switch") @Override public Component getListCellRendererComponent(JList list, User value, int index, boolean isSelected, boolean cellHasFocus) { if (isSelected) { From 23d7d6b164e9a786999bbd8ca92bc8f66c15cf6d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Fri, 20 Dec 2019 15:05:31 +0100 Subject: [PATCH 129/474] Saving settings and local database on application exit Fixes #55 --- src/main/java/envoy/client/ui/ChatWindow.java | 21 +------------------ src/main/java/envoy/client/ui/Startup.java | 14 +++++++++++++ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 8814195..e94c32b 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -8,9 +8,6 @@ import java.awt.Insets; import java.awt.Toolkit; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -30,10 +27,9 @@ import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; import envoy.client.Settings; -import envoy.client.util.EnvoyLog; import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; - +import envoy.client.util.EnvoyLog; import envoy.schema.Message; import envoy.schema.User; @@ -80,21 +76,6 @@ public class ChatWindow extends JFrame { setLocationRelativeTo(null); setIconImage(Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); - // Save chats when window closes - addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(WindowEvent evt) { - try { - localDB.save(); - Settings.getInstance().save(); - } catch (IOException e1) { - e1.printStackTrace(); - logger.log(Level.WARNING, "Unable to save the messages", e1); - } - } - }); - contentPane.setBorder(new EmptyBorder(space, space, space, space)); setContentPane(contentPane); GridBagLayout gbl_contentPane = new GridBagLayout(); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index b9f9633..d011bab 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -11,6 +11,7 @@ import javax.swing.JOptionPane; import envoy.client.Client; import envoy.client.Config; import envoy.client.LocalDB; +import envoy.client.Settings; import envoy.client.util.EnvoyLog; import envoy.exception.EnvoyException; import envoy.schema.User; @@ -126,5 +127,18 @@ public class Startup { e.printStackTrace(); } }); + + // Save Settings and LocalDB on shutdown + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + logger.info("Saving local database..."); + localDB.save(); + logger.info("Saving settings..."); + Settings.getInstance().save(); + } catch (IOException e1) { + e1.printStackTrace(); + logger.log(Level.WARNING, "Unable to save the messages", e1); + } + })); } } \ No newline at end of file From ccff438c7fdd60e9c205cb6ba6a6af459c1623c8 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Fri, 20 Dec 2019 20:25:54 +0100 Subject: [PATCH 130/474] Added and fixed existing Javadoc, configured Javadoc validation --- .classpath | 6 ++ .settings/org.eclipse.jdt.core.prefs | 30 ++++++++-- src/main/java/envoy/client/Chat.java | 17 +++++- src/main/java/envoy/client/Config.java | 19 +++++-- src/main/java/envoy/client/LocalDB.java | 8 +-- src/main/java/envoy/client/Settings.java | 56 ++++++++++--------- .../java/envoy/client/event/MessageEvent.java | 6 ++ .../envoy/client/event/ThemeChangeEvent.java | 6 ++ src/main/java/envoy/client/ui/ChatWindow.java | 14 +++-- .../envoy/client/ui/MessageListRenderer.java | 5 +- src/main/java/envoy/client/ui/Startup.java | 14 ++++- src/main/java/envoy/client/ui/Theme.java | 47 ++++++++++++---- .../envoy/client/ui/UserListRenderer.java | 4 +- 13 files changed, 167 insertions(+), 65 deletions(-) diff --git a/.classpath b/.classpath index 906bfce..8bcb665 100644 --- a/.classpath +++ b/.classpath @@ -28,5 +28,11 @@ + + + + + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 262bd4f..4d86470 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -8,10 +8,18 @@ org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary= org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable org.eclipse.jdt.core.compiler.annotation.nullable.secondary= org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled org.eclipse.jdt.core.compiler.problem.APILeak=warning org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.autoboxing=ignore org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning org.eclipse.jdt.core.compiler.problem.deadCode=warning @@ -21,6 +29,7 @@ org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod= org.eclipse.jdt.core.compiler.problem.discouragedReference=warning org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled @@ -33,12 +42,25 @@ org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=info +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=public org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=info +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_tags +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=info +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning @@ -61,8 +83,8 @@ org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore -org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore -org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore @@ -74,7 +96,7 @@ org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning -org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore @@ -95,7 +117,7 @@ org.eclipse.jdt.core.compiler.problem.unusedImport=warning org.eclipse.jdt.core.compiler.problem.unusedLabel=warning org.eclipse.jdt.core.compiler.problem.unusedLocal=warning org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore -org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=warning org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index da35bd3..4f13cee 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -7,6 +7,19 @@ import javax.swing.DefaultListModel; import envoy.schema.Message; import envoy.schema.User; +/** + * Represents a chat between two {@link User}s
+ * as a list of {@link Message} objects. + *
+ * Project: envoy-client
+ * File: Chat.java
+ * Created: 19 Oct 2019
+ * + * @author Maximilian Käfer + * @author Leon Hofmeister + * @author Kai S. K. Engelbart + * @since Envoy v0.1-alpha + */ public class Chat implements Serializable { private static final long serialVersionUID = -7751248474547242056L; @@ -17,7 +30,7 @@ public class Chat implements Serializable { /** * Provides the list of messages that the recipient receives.
* Saves the Messages in the corresponding chat at that Point. - * + * * @param recipient the user who receives the messages * @since Envoy v0.1-alpha */ @@ -31,7 +44,7 @@ public class Chat implements Serializable { /** * Adds the received message at the current Point in the current chat - * + * * @param message the message to add in said chat * @since Envoy v0.1-alpha */ diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 0c3a000..e28dc92 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -6,10 +6,15 @@ import java.util.Properties; import envoy.exception.EnvoyException; /** + * Manages all application settings that are set during application startup by + * either loading them from the {@link Properties} file + * {@code client.properties} or parsing them from the command line arguments of + * the application.
+ *
* Project: envoy-client
* File: Config.java
* Created: 12 Oct 2019
- * + * * @author Kai S. K. Engelbart * @since Envoy v0.1-alpha */ @@ -24,6 +29,9 @@ public class Config { private Config() {} + /** + * @return the singleton instance of the {@link Config} + */ public static Config getInstance() { if (config == null) config = new Config(); return config; @@ -34,7 +42,7 @@ public class Config { * This file contains information about * the server and port, as well as the path to the local * database and the synchronization timeout - * + * * @throws EnvoyException if the {@code client.properties} file could not be * loaded * @since Envoy v0.1-alpha @@ -56,7 +64,7 @@ public class Config { /** * Sets the server, port and localDB path via command line properties --server / * -s, --port / -p and --localDB / -db. - * + * * @param args the command line arguments to parse * @throws EnvoyException if the command line arguments contain an unknown token * @since Envoy v0.1-alpha @@ -96,7 +104,7 @@ public class Config { /** * Changes the default server host name. * Exclusively intended for development purposes. - * + * * @param server the host name of the Envoy server * @since Envoy v0.1-alpha */ @@ -111,7 +119,7 @@ public class Config { /** * Changes the default port. * Exclusively intended for development purposes. - * + * * @param port the port where an Envoy server is located * @since Envoy v0.1-alpha */ @@ -143,5 +151,4 @@ public class Config { * @since Envoy v0.1-alpha */ public void setSyncTimeout(int syncTimeout) { this.syncTimeout = syncTimeout; } - } diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 61e7461..8c6a40b 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -56,7 +56,7 @@ public class LocalDB { * system, call {@link LocalDB#initializeDBFile()}. * * @param localDBDir the directory in which to store users and chats - * @throws IOException if the LocalDB could not be initialised + * @throws IOException if the LocalDB could not be initialized * @since Envoy v0.1-alpha */ public LocalDB(File localDBDir) throws IOException { @@ -102,7 +102,7 @@ public class LocalDB { /** * Loads all users that are stored in the local database. - * + * * @throws EnvoyException if the loading process failed * @since Envoy v0.2-alpha */ @@ -170,7 +170,7 @@ public class LocalDB { /** * Creates a {@link Sync} object filled with the changes that occurred to the * local database since the last synchronization. - * + * * @param userId the ID of the user that is synchronized by this client * @return {@link Sync} object filled with the current changes * @since Envoy v0.1-alpha @@ -187,7 +187,7 @@ public class LocalDB { /** * Applies the changes carried by a {@link Sync} object to the local database - * + * * @param returnSync the {@link Sync} object to apply * @since Envoy v0.1-alpha */ diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index ea789c8..75a4355 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -14,10 +14,14 @@ import java.util.prefs.Preferences; import envoy.client.ui.Theme; /** + * Manages all application settings, which are different objects that can be + * changed during runtime and serialized them by using either the file system or + * the {@link Preferences} API.
+ *
* Project: envoy-client
* File: Settings.java
* Created: 11 Nov 2019
- * + * * @author Leon Hofmeister * @author Maximilian Käfer * @author Kai S. K. Engelbart @@ -48,14 +52,14 @@ public class Settings { /** * The way to instantiate the settings. * Is set to private to deny other instances of that object. - * + * * @since Envoy v0.2-alpha */ private Settings() { load(); } /** * This method is used to ensure that there is only one instance of Settings. - * + * * @return the instance of Settings * @since Envoy v0.2-alpha */ @@ -87,8 +91,9 @@ public class Settings { /** * Updates the preferences when the save button is clicked. - * - * @throws IOException if something went wrong while saving + * + * @throws IOException if an error occurs while saving the themes to the theme + * file * @since Envoy v0.2-alpha */ public void save() throws IOException { @@ -103,56 +108,55 @@ public class Settings { } /** - * adds new theme to the theme map and sets current theme to the new theme. - * - * @param theme the theme to add + * Adds new theme to the theme map. + * + * @param theme the {@link Theme} to add * @since Envoy v0.2-alpha */ - public void addNewThemeToMap(Theme theme) { - settings.getThemes().put(theme.getThemeName(), theme); - // currentTheme = theme.getThemeName(); - } + public void addNewThemeToMap(Theme theme) { settings.getThemes().put(theme.getThemeName(), theme); } /** - * @return the name of the current theme + * @return the name of the currently active {@link Theme} * @since Envoy v0.2-alpha */ public String getCurrentTheme() { return currentTheme; } /** - * Sets the currentTheme - * - * @param themeName the name of the new current theme + * Sets the name of the current {@link Theme}. + * + * @param themeName the name to set * @since Envoy v0.2-alpha */ public void setCurrentTheme(String themeName) { currentTheme = themeName; } /** - * @return true, if "enter" suffices to send a message, else it has to be "ctrl" - * + "enter" + * @return {@code true}, if pressing the {@code Enter} key suffices to send a + * message. Otherwise it has to be pressed in conjunction with the + * {@code Control} key. * @since Envoy v0.2-alpha */ public boolean isEnterToSend() { return enterToSend; } /** - * Change mode of posting a message via Keystroke. - * - * @param enterToSend if true, "enter" suffices to send a message,
- * else it has to be "ctrl" + "enter" + * Changes the keystrokes performed by the user to send a message. + * + * @param enterToSend If set to {@code true} a message can be sent by pressing + * the {@code Enter} key. Otherwise it has to be pressed in + * conjunction with the {@code Control} key. * @since Envoy v0.2-alpha */ public void setEnterToSend(boolean enterToSend) { this.enterToSend = enterToSend; } /** - * @return the map of all themes + * @return a {@code Map} of all themes with their names as keys * @since Envoy v0.2-alpha */ public Map getThemes() { return themes; } /** - * Sets the map of all themes - * - * @param themes a map(String, Theme) of all themes + * Sets the {@code Map} of all themes with their names as keys + * + * @param themes the theme map to set * @since Envoy v0.2-alpha */ public void setThemes(Map themes) { this.themes = themes; } diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java index 014a7bb..8eb7384 100644 --- a/src/main/java/envoy/client/event/MessageEvent.java +++ b/src/main/java/envoy/client/event/MessageEvent.java @@ -13,6 +13,12 @@ public class MessageEvent implements Event { protected final Message message; + /** + * Initializes a {@link MessageEvent} conveying information about a + * {@link Message} object. + * + * @param message the {@link Message} object to attach to this event + */ public MessageEvent(Message message) { this.message = message; } @Override diff --git a/src/main/java/envoy/client/event/ThemeChangeEvent.java b/src/main/java/envoy/client/event/ThemeChangeEvent.java index d3ba96b..84e6218 100644 --- a/src/main/java/envoy/client/event/ThemeChangeEvent.java +++ b/src/main/java/envoy/client/event/ThemeChangeEvent.java @@ -13,6 +13,12 @@ public class ThemeChangeEvent implements Event { private final Theme theme; + /** + * Initializes a {@link ThemeChangeEvent} conveying information about the change + * of the {@link Theme} currently in use + * + * @param theme the new currently used {@link Theme} object + */ public ThemeChangeEvent(Theme theme) { this.theme = theme; } @Override diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index e94c32b..ea8ab1e 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -66,6 +66,13 @@ public class ChatWindow extends JFrame { private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class.getSimpleName()); + /** + * Initializes a {@link JFrame} with UI elements used to send and read messages + * to different users. + * + * @param client the {@link Client} used to send and receive messages + * @param localDB the {@link LocalDB} used to manage stored messages and users + */ public ChatWindow(Client client, LocalDB localDB) { this.client = client; this.localDB = localDB; @@ -112,9 +119,8 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER - && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) postMessage(messageList); - } } }); @@ -219,8 +225,8 @@ public class ChatWindow extends JFrame { /** * Used to immediately reload the ChatWindow when settings were changed. - * - * @param theme the theme to change colors into + * + * @param theme the theme to change colors into * @since Envoy v0.1-alpha */ private void changeChatWindowColors(Theme theme) { diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 9be79c5..5623fb6 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -14,11 +14,10 @@ import envoy.schema.Message; /** * Defines how a message is displayed.
*
- * * Project: envoy-client
* File: UserListRenderer.java
* Created: 19 Oct 2019
- * + * * @author Kai S. K. Engelbart * @author Maximilian Käfer * @since Envoy v0.1-alpha @@ -62,7 +61,7 @@ public class MessageListRenderer extends JLabel implements ListCellRendererenvoy-client
* File: Startup.java
* Created: 12 Oct 2019
- * + * * @author Leon Hofmeister * @author Maximilian Käfer * @author Kai S. K. Engelbart @@ -32,6 +32,16 @@ public class Startup { private static final Logger logger = EnvoyLog.getLogger(Startup.class.getSimpleName()); + /** + * Loads the application by first loading the configuration, then acquiring a + * user name and connecting to the server. If the server cannot be reached, + * offline mode is entered if possible. After that, a {@link ChatWindow} + * instance is initialized and then displayed to the user. Upon application + * exit, settings and the local database are saved. + * + * @param args the command line arguments may contain configuration parameters + * and are parsed by the {@link Config} class + */ public static void main(String[] args) { Config config = Config.getInstance(); @@ -127,7 +137,7 @@ public class Startup { e.printStackTrace(); } }); - + // Save Settings and LocalDB on shutdown Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index 66a0a80..78eccc6 100644 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -7,7 +7,7 @@ import java.io.Serializable; * Project: envoy-client
* File: Theme.java
* Created: 23 Nov 2019
- * + * * @author Maximilian Käfer * @since Envoy v0.2-alpha */ @@ -26,6 +26,22 @@ public class Theme implements Serializable { private Color selectionColor; private Color typingMessageColor; + /** + * Initializes a {@link Theme} with all colors relevant to the application GUI. + * + * @param themeName the name of the {@link Theme} + * @param backgroundColor the background color + * @param cellColor the cell color + * @param interactableForegroundColor the color of interactable foreground UI + * elements + * @param interactableBackgroundColor the color of interactable background UI + * elements + * @param messageColorChat the color of chat messages + * @param dateColorChat the color of chat message metadata + * @param selectionColor the section color + * @param typingMessageColor the color of currently typed messages + * @param userNameColor the color of user names + */ public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, Color interactableBackgroundColor, Color messageColorChat, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) { @@ -42,6 +58,13 @@ public class Theme implements Serializable { this.userNameColor = userNameColor; } + /** + * Initializes a {@link Theme} by copying all parameters except for the name + * from another {@link Theme} instance. + * + * @param name the name of the {@link Theme} + * @param other the {@link Theme} to copy + */ public Theme(String name, Theme other) { this(name, other.backgroundColor, other.cellColor, other.interactableForegroundColor, other.interactableBackgroundColor, other.messageColorChat, other.dateColorChat, other.selectionColor, @@ -110,7 +133,7 @@ public class Theme implements Serializable { /** * Sets the a specific {@link Color} in this theme to a new {@link Color} - * + * * @param index - index of the color
* 0 = backgroundColor
* 1 = cellColor
@@ -122,38 +145,38 @@ public class Theme implements Serializable { * 7 = typingMessageColor
* 8 = userNameColor
*
- * + * * @param newColor - new {@link Color} to be set * @since Envoy 0.2-alpha */ public void setColor(int index, Color newColor) { switch (index) { case 0: - this.backgroundColor = newColor; + backgroundColor = newColor; break; case 1: - this.cellColor = newColor; + cellColor = newColor; break; case 2: - this.interactableForegroundColor = newColor; + interactableForegroundColor = newColor; break; case 3: - this.interactableBackgroundColor = newColor; + interactableBackgroundColor = newColor; break; case 4: - this.messageColorChat = newColor; + messageColorChat = newColor; break; case 5: - this.dateColorChat = newColor; + dateColorChat = newColor; break; case 6: - this.selectionColor = newColor; + selectionColor = newColor; break; case 7: - this.typingMessageColor = newColor; + typingMessageColor = newColor; break; case 8: - this.userNameColor = newColor; + userNameColor = newColor; break; } } diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index 1ee3f84..d26aa8b 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -17,7 +17,7 @@ import envoy.schema.User.UserStatus; * Project: envoy-client
* File: UserListRenderer.java
* Created: 12 Oct 2019
- * + * * @author Kai S. K. Engelbart * @author Maximilian Käfer * @since Envoy v0.1-alpha @@ -58,7 +58,7 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { return this; } - public String toHex(Color c) { + private String toHex(Color c) { int r = c.getRed(); int g = c.getGreen(); int b = c.getBlue(); From b0ce8fe3401ac793edc7f5ee14159e1cc184e23c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 00:29:16 +0100 Subject: [PATCH 131/474] Refined theme customization mechanism * Created abstract SettingsPanel class for defining settings screen pages * Moves theme customization related settings to new class ThemeCustomizationPanel * Changes Theme to use a map internally --- src/main/java/envoy/client/ui/ChatWindow.java | 2 +- .../java/envoy/client/ui/SettingsScreen.java | 458 ------------------ src/main/java/envoy/client/ui/Theme.java | 109 ++--- .../client/ui/settings/SettingsPanel.java | 23 + .../client/ui/settings/SettingsScreen.java | 187 +++++++ .../ui/settings/ThemeCustomizationPanel.java | 252 ++++++++++ src/main/resources/envoy_logo_old.png | Bin 8152 -> 0 bytes 7 files changed, 496 insertions(+), 535 deletions(-) delete mode 100644 src/main/java/envoy/client/ui/SettingsScreen.java create mode 100644 src/main/java/envoy/client/ui/settings/SettingsPanel.java create mode 100644 src/main/java/envoy/client/ui/settings/SettingsScreen.java create mode 100644 src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java delete mode 100644 src/main/resources/envoy_logo_old.png diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index ea8ab1e..8b1c60c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -29,6 +29,7 @@ import envoy.client.LocalDB; import envoy.client.Settings; import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; +import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; import envoy.schema.Message; import envoy.schema.User; @@ -157,7 +158,6 @@ public class ChatWindow extends JFrame { settingsButton.addActionListener((evt) -> { try { new SettingsScreen().setVisible(true); - changeChatWindowColors(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); } catch (Exception e) { logger.log(Level.WARNING, "An error occured while opening the settings screen", e); e.printStackTrace(); diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java deleted file mode 100644 index 75ce884..0000000 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ /dev/null @@ -1,458 +0,0 @@ -package envoy.client.ui; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.util.Arrays; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.swing.BoxLayout; -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JColorChooser; -import javax.swing.JComboBox; -import javax.swing.JDialog; -import javax.swing.JList; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextPane; -import javax.swing.ListSelectionModel; - -import envoy.client.Settings; -import envoy.client.util.EnvoyLog; -import envoy.client.event.EventBus; -import envoy.client.event.ThemeChangeEvent; - -/** - * This class provides the GUI to change the user specific settings. - * - * Project: envoy-client
- * File: SettingsScreen.java
- * Created: 31 Oct 2019
- * - * @author Leon Hofmeister - * @author Maximilian Käfer - * @author Kai S. K. Engelbart - */ -public class SettingsScreen extends JDialog { - - private static final long serialVersionUID = -4476913491263077107L; - private final JPanel contentPanel = new JPanel(); - - private DefaultListModel optionsListModel = new DefaultListModel<>(); - private final JList options = new JList<>(); - private JPanel buttonPane = new JPanel(); - - private JPanel themeContent = new JPanel(); - private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]); - private JComboBox themes = new JComboBox<>(themeArray); - - private GridBagConstraints gbc_themeContent = new GridBagConstraints(); - - private JButton createNewThemeButton = new JButton("Create New Theme"); - private JPanel colorsPanel = new JPanel(); - private JButton okButton = new JButton("Save"); - private JButton cancelButton = new JButton("Cancel"); - - private static int space = 5; - - private Theme temporaryTheme, selectedTheme; - - private static final Logger logger = EnvoyLog.getLogger(SettingsScreen.class.getSimpleName()); - - /** - * Builds the settings screen. - * - * @since Envoy v0.1-alpha - */ - public SettingsScreen() { - logger.info(Settings.getInstance().getCurrentTheme()); - - setBounds(10, 10, 450, 650); - getContentPane().setLayout(new BorderLayout()); - { - - createNewThemeButton.setEnabled(false); - - temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); - - // Content pane - GridBagLayout gbl_contentPanel = new GridBagLayout(); - - gbl_contentPanel.columnWidths = new int[] { 1, 1 }; - gbl_contentPanel.rowHeights = new int[] { 1 }; - gbl_contentPanel.columnWeights = new double[] { 0.05, 1.0 }; - gbl_contentPanel.rowWeights = new double[] { 1.0 }; - - getContentPane().add(contentPanel, BorderLayout.CENTER); - contentPanel.setLayout(gbl_contentPanel); - - options.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - - options.addListSelectionListener((listSelectionEvent) -> { - if (!listSelectionEvent.getValueIsAdjusting()) { - @SuppressWarnings("unchecked") - final JList selectedOption = (JList) listSelectionEvent.getSource(); - final String option = selectedOption.getSelectedValue(); - logger.log(Level.FINEST, option); - - switch (option) { - case "Color Themes": - setContent(themeContent, gbc_themeContent); - getContentPane().repaint(); - getContentPane().revalidate(); - break; - } - } - }); - - options.setFont(new Font("Arial", Font.PLAIN, 14)); - - Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - - GridBagConstraints gbc_optionsList = new GridBagConstraints(); - gbc_optionsList.fill = GridBagConstraints.BOTH; - gbc_optionsList.gridx = 0; - gbc_optionsList.gridy = 0; - gbc_optionsList.anchor = GridBagConstraints.PAGE_START; - gbc_optionsList.insets = new Insets(space, space, space, space); - - optionsListModel.addElement("Color Themes"); - options.setModel(optionsListModel); - contentPanel.add(options, gbc_optionsList); - - // Theme content - gbc_themeContent = new GridBagConstraints(); - gbc_themeContent.fill = GridBagConstraints.BOTH; - gbc_themeContent.gridx = 1; - gbc_themeContent.gridy = 0; - gbc_themeContent.anchor = GridBagConstraints.PAGE_START; - gbc_themeContent.insets = new Insets(space, space, space, space); - - GridBagLayout gbl_themeLayout = new GridBagLayout(); - - gbl_themeLayout.columnWidths = new int[] { 1, 1 }; - gbl_themeLayout.rowHeights = new int[] { 1, 1 }; - gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 }; - gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0 }; - - themeContent.setLayout(gbl_themeLayout); - - themes.setSelectedItem(Settings.getInstance().getCurrentTheme()); - - themes.addItemListener(new ItemListener() { - - @Override - public void itemStateChanged(ItemEvent e) { - String selectedValue = (String) themes.getSelectedItem(); - logger.log(Level.FINEST, selectedValue); - selectedTheme = Settings.getInstance().getThemes().get(selectedValue); - } - }); - - GridBagConstraints gbc_themes = new GridBagConstraints(); - gbc_themes.fill = GridBagConstraints.HORIZONTAL; - gbc_themes.gridx = 0; - gbc_themes.gridy = 0; - gbc_themes.anchor = GridBagConstraints.NORTHWEST; - gbc_themes.insets = new Insets(space, space, space, space); - - themeContent.add(themes, gbc_themes); - - colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); - colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getBackgroundColor(), "Background", 0); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getCellColor(), "Cells", 1); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getInteractableForegroundColor(), - "Interactable Foreground", - 2); - buildCustomizeElement(new JPanel(), - new JButton(), - new JTextPane(), - theme, - theme.getInteractableBackgroundColor(), - "Interactable Background", - 3); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getMessageColorChat(), "Messages Chat", 4); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getDateColorChat(), "Date Chat", 5); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getSelectionColor(), "Selection", 6); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getTypingMessageColor(), "Typing Message", 7); - buildCustomizeElement(new JPanel(), new JButton(), new JTextPane(), theme, theme.getUserNameColor(), "User Names", 8); - - GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); - gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; - gbc_colorsPanel.gridx = 0; - gbc_colorsPanel.gridy = 1; - gbc_colorsPanel.gridwidth = 2; - gbc_colorsPanel.anchor = GridBagConstraints.NORTHWEST; - gbc_colorsPanel.insets = new Insets(space, 0, 0, 0); - - themeContent.add(colorsPanel, gbc_colorsPanel); - - createNewThemeButton.setBackground(theme.getInteractableBackgroundColor()); - createNewThemeButton.setForeground(theme.getInteractableForegroundColor()); - colorsPanel.setBackground(theme.getCellColor()); - - createNewThemeButton.addActionListener((evt) -> { - try { - String s = JOptionPane.showInputDialog("Enter a name for the new theme"); - logger.log(Level.FINEST, s); - Settings.getInstance() - .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(), - temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(), - temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), - temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor())); - themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); - themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName(); - - temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); - - createNewThemeButton.setEnabled(false); - themes.addItem(themeArray[themeArray.length - 1]); - - contentPanel.revalidate(); - contentPanel.repaint(); - - } catch (Exception e) { - logger.info("New theme couldn't be created! " + e); - e.printStackTrace(); - } - }); - - GridBagConstraints gbc_createNewTheme = new GridBagConstraints(); - gbc_createNewTheme.gridx = 0; - gbc_createNewTheme.gridy = 10; - - colorsPanel.add(createNewThemeButton, gbc_createNewTheme); - - // ButtonPane------------------------------------------------------- - GridBagLayout gbl_buttonPane = new GridBagLayout(); - gbl_buttonPane.columnWidths = new int[] { 100, 250, 100, 0 }; - gbl_buttonPane.rowHeights = new int[] { 25, 0 }; - gbl_buttonPane.columnWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE }; - gbl_buttonPane.rowWeights = new double[] { 0.0, Double.MIN_VALUE }; - - getContentPane().add(buttonPane, BorderLayout.SOUTH); - buttonPane.setLayout(gbl_buttonPane); - { - cancelButton.setActionCommand("Cancel"); - cancelButton.setBorderPainted(false); - GridBagConstraints gbc_cancelButton = new GridBagConstraints(); - gbc_cancelButton.anchor = GridBagConstraints.NORTHWEST; - gbc_cancelButton.insets = new Insets(space, space, space, space); - gbc_cancelButton.gridx = 0; - gbc_cancelButton.gridy = 0; - buttonPane.add(cancelButton, gbc_cancelButton); - - cancelButton.addActionListener((evt) -> { dispose(); }); - } - { - okButton.setActionCommand("OK"); - okButton.setBorderPainted(false); - GridBagConstraints gbc_okButton = new GridBagConstraints(); - gbc_okButton.anchor = GridBagConstraints.NORTHEAST; - gbc_okButton.fill = GridBagConstraints.EAST; - gbc_okButton.insets = new Insets(space, space, space, space); - gbc_okButton.gridx = 2; - gbc_okButton.gridy = 0; - buttonPane.add(okButton, gbc_okButton); - getRootPane().setDefaultButton(okButton); - okButton.addActionListener((evt) -> { - try { - Settings.getInstance().setEnterToSend(Settings.getInstance().isEnterToSend());// still temporary - - Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); - logger.log(Level.FINER, selectedTheme.getThemeName()); - - final Theme currentTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - changeSettingsScreenColors(currentTheme); - updateColorVariables(currentTheme); - EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); - Settings.getInstance().save(); - - revalidate(); - repaint(); - } catch (Exception e) { - logger.warning("Something went wrong when changing the setting"); - JOptionPane.showMessageDialog(this, "Something went wrong when changing the setting"); - dispose(); - } - }); - } - } - - changeSettingsScreenColors(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); - - setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - setModal(true); - } - - private void changeSettingsScreenColors(Theme theme) { - // whole JDialog - setBackground(theme.getBackgroundColor()); - // contentPanel - contentPanel.setBackground(theme.getBackgroundColor()); - // buttonPane - buttonPane.setBackground(theme.getCellColor()); - // cancelButton - cancelButton.setBackground(theme.getInteractableBackgroundColor()); - cancelButton.setForeground(theme.getInteractableForegroundColor()); - // okButton - okButton.setBackground(theme.getInteractableBackgroundColor()); - okButton.setForeground(theme.getInteractableForegroundColor()); - // options - options.setSelectionForeground(theme.getUserNameColor()); - options.setSelectionBackground(theme.getSelectionColor()); - options.setForeground(theme.getUserNameColor()); - options.setBackground(theme.getCellColor()); - // themeContent - themeContent.setForeground(theme.getUserNameColor()); - themeContent.setBackground(theme.getCellColor()); - // themes - themes.setBackground(theme.getBackgroundColor()); - themes.setForeground(getInvertedColor(theme.getBackgroundColor())); - - createNewThemeButton.setBackground(theme.getInteractableBackgroundColor()); - createNewThemeButton.setForeground(theme.getInteractableForegroundColor()); - colorsPanel.setBackground(theme.getCellColor()); - - } - - private void updateColorVariables(Theme theme) { - temporaryTheme = new Theme("temporaryTheme", theme); - - colorsPanel.removeAll(); - - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getBackgroundColor(), - "Background", - 0); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getCellColor(), - "Cells", - 1); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getInteractableForegroundColor(), - "Interactable Foreground", - 2); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getInteractableBackgroundColor(), - "Interactable Background", - 3); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getMessageColorChat(), - "Messages Chat", - 4); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getDateColorChat(), - "Date Chat", - 5); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getSelectionColor(), - "Selection", - 6); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getTypingMessageColor(), - "Typing Message", - 7); - buildCustomizeElement(new JPanel(), - - new JButton(), - new JTextPane(), - theme, - theme.getUserNameColor(), - "User Names", - 8); - - GridBagConstraints gbc_createNewTheme = new GridBagConstraints(); - gbc_createNewTheme.gridx = 0; - gbc_createNewTheme.gridy = 10; - - colorsPanel.add(createNewThemeButton, gbc_createNewTheme); - } - - private void setContent(JPanel content, GridBagConstraints layout) { contentPanel.add(content, layout); } - - private void buildCustomizeElement(JPanel panel, JButton button, JTextPane textPane, Theme theme, Color color, String name, int yIndex) { - textPane.setFont(new Font("Arial", Font.PLAIN, 14)); - textPane.setBackground(theme.getBackgroundColor()); - textPane.setForeground(getInvertedColor(theme.getBackgroundColor())); - textPane.setText(name); - textPane.setEditable(false); - - button.setBackground(color); - button.setPreferredSize(new Dimension(25, 25)); - - button.addActionListener((evt) -> { - try { - Color newColor = JColorChooser.showDialog(null, "Choose a color", color); - if (newColor.getRGB() != color.getRGB()) { - logger.log(Level.FINEST, "New Color: " + String.valueOf(color.getRGB())); - // TODO: When Theme changed in same settings screen, color variable doesnt - // update. - temporaryTheme.setColor(yIndex, newColor); - createNewThemeButton.setEnabled(true); - } - button.setBackground(newColor); - - } catch (Exception e) { - logger.info("An error occured while opening Color Chooser: " + e); - e.printStackTrace(); - } - }); - - panel.add(textPane); - panel.add(button); - panel.setBackground(theme.getCellColor()); - panel.setAlignmentX(Component.LEFT_ALIGNMENT); - - colorsPanel.add(panel); - } - - private Color getInvertedColor(Color color) { return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); } -} diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index 78eccc6..c498655 100644 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -2,6 +2,8 @@ package envoy.client.ui; import java.awt.Color; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; /** * Project: envoy-client
@@ -15,16 +17,8 @@ public class Theme implements Serializable { private static final long serialVersionUID = 141727847527060352L; - private String themeName; - private Color backgroundColor; - private Color cellColor; - private Color interactableBackgroundColor; - private Color userNameColor; - private Color interactableForegroundColor; - private Color messageColorChat; - private Color dateColorChat; - private Color selectionColor; - private Color typingMessageColor; + private String themeName; + private Map colors = new HashMap<>(); /** * Initializes a {@link Theme} with all colors relevant to the application GUI. @@ -47,15 +41,15 @@ public class Theme implements Serializable { this.themeName = themeName; - this.backgroundColor = backgroundColor; - this.cellColor = cellColor; - this.interactableForegroundColor = interactableForegroundColor; - this.interactableBackgroundColor = interactableBackgroundColor; - this.messageColorChat = messageColorChat; - this.dateColorChat = dateColorChat; - this.selectionColor = selectionColor; - this.typingMessageColor = typingMessageColor; - this.userNameColor = userNameColor; + colors.put("backgroundColor", backgroundColor); + colors.put("cellColor", cellColor); + colors.put("interactableForegroundColor", interactableForegroundColor); + colors.put("interactableBackgroundColor", interactableBackgroundColor); + colors.put("messageColorChat", messageColorChat); + colors.put("dateColorChat", dateColorChat); + colors.put("selectionColor", selectionColor); + colors.put("typingMessageColor", typingMessageColor); + colors.put("userNameColor", userNameColor); } /** @@ -66,11 +60,16 @@ public class Theme implements Serializable { * @param other the {@link Theme} to copy */ public Theme(String name, Theme other) { - this(name, other.backgroundColor, other.cellColor, other.interactableForegroundColor, - other.interactableBackgroundColor, other.messageColorChat, other.dateColorChat, other.selectionColor, - other.typingMessageColor, other.userNameColor); + themeName = name; + colors.putAll(other.colors); } + /** + * @return a {@code Map} of all colors defined for this theme + * with their names as keys + */ + public Map getColors() { return colors; } + /** * @return name of the theme * @since Envoy v0.2-alpha @@ -81,104 +80,62 @@ public class Theme implements Serializable { * @return interactableForegroundColor * @since Envoy v0.2-alpha */ - public Color getInteractableForegroundColor() { return interactableForegroundColor; } + public Color getInteractableForegroundColor() { return colors.get("interactableForegroundColor"); } /** * @return messageColorChat * @since Envoy v0.2-alpha */ - public Color getMessageColorChat() { return messageColorChat; } + public Color getMessageColorChat() { return colors.get("messageColorChat"); } /** * @return dateColorChat * @since Envoy v0.2-alpha */ - public Color getDateColorChat() { return dateColorChat; } + public Color getDateColorChat() { return colors.get("dateColorChat"); } /** * @return selectionColor * @since Envoy v0.2-alpha */ - public Color getSelectionColor() { return selectionColor; } + public Color getSelectionColor() { return colors.get("selectionColor"); } /** * @return typingMessageColor * @since Envoy v0.2-alpha */ - public Color getTypingMessageColor() { return typingMessageColor; } + public Color getTypingMessageColor() { return colors.get("typingMessageColor"); } /** * @return backgroundColor * @since Envoy v0.2-alpha */ - public Color getBackgroundColor() { return backgroundColor; } + public Color getBackgroundColor() { return colors.get("backgroundColor"); } /** * @return cellColor * @since Envoy v0.2-alpha */ - public Color getCellColor() { return cellColor; } + public Color getCellColor() { return colors.get("cellColor"); } /** * @return interactableBackgroundColor * @since Envoy v0.2-alpha */ - public Color getInteractableBackgroundColor() { return interactableBackgroundColor; } + public Color getInteractableBackgroundColor() { return colors.get("interactableBackgroundColor"); } /** * @return userNameColor * @since Envoy v0.2-alpha */ - public Color getUserNameColor() { return userNameColor; } + public Color getUserNameColor() { return colors.get("userNameColor"); } /** * Sets the a specific {@link Color} in this theme to a new {@link Color} * - * @param index - index of the color
- * 0 = backgroundColor
- * 1 = cellColor
- * 2 = interactableForegroundColor
- * 3 = interactableBackgroundColor
- * 4 = messageColorChat
- * 5 = dateColorChat
- * 6 = selectionColor
- * 7 = typingMessageColor
- * 8 = userNameColor
- *
- * - * @param newColor - new {@link Color} to be set + * @param colorName the name of the {@link Color} to set + * @param newColor the new {@link Color} to be set * @since Envoy 0.2-alpha */ - public void setColor(int index, Color newColor) { - switch (index) { - case 0: - backgroundColor = newColor; - break; - case 1: - cellColor = newColor; - break; - case 2: - interactableForegroundColor = newColor; - break; - case 3: - interactableBackgroundColor = newColor; - break; - case 4: - messageColorChat = newColor; - break; - case 5: - dateColorChat = newColor; - break; - case 6: - selectionColor = newColor; - break; - case 7: - typingMessageColor = newColor; - break; - case 8: - userNameColor = newColor; - break; - } - } - + public void setColor(String colorName, Color newColor) { colors.put(colorName, newColor); } } diff --git a/src/main/java/envoy/client/ui/settings/SettingsPanel.java b/src/main/java/envoy/client/ui/settings/SettingsPanel.java new file mode 100644 index 0000000..56e1957 --- /dev/null +++ b/src/main/java/envoy/client/ui/settings/SettingsPanel.java @@ -0,0 +1,23 @@ +package envoy.client.ui.settings; + +import java.awt.event.ActionListener; + +import javax.swing.JPanel; + +/** + * Project: envoy-client
+ * File: SettingsPanel.java
+ * Created: 20 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public abstract class SettingsPanel extends JPanel { + + private static final long serialVersionUID = -3069212622468626050L; + + /** + * @return an {@link ActionListener} that should be invoked when the OK button + * is pressed in the {@link SettingsScreen} + */ + public abstract ActionListener getOkButtonAction(); +} diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java new file mode 100644 index 0000000..d34eee4 --- /dev/null +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -0,0 +1,187 @@ +package envoy.client.ui.settings; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListSelectionModel; + +import envoy.client.Settings; +import envoy.client.event.EventBus; +import envoy.client.event.ThemeChangeEvent; +import envoy.client.ui.Theme; +import envoy.client.util.EnvoyLog; + +/** + * This class provides the GUI to change the user specific settings.
+ *
+ * Project: envoy-client
+ * File: SettingsScreen.java
+ * Created: 31 Oct 2019
+ * + * @author Leon Hofmeister + * @author Maximilian Käfer + * @author Kai S. K. Engelbart + */ +public class SettingsScreen extends JDialog { + + private static final long serialVersionUID = -4476913491263077107L; + + private final JPanel contentPanel = new JPanel(); + + // Settings panel list + private final DefaultListModel optionsListModel = new DefaultListModel<>(); + private final JList options = new JList<>(optionsListModel); + + // OK and cancel buttons + private final JPanel buttonPane = new JPanel(); + private final JButton okButton = new JButton("Save"); + private final JButton cancelButton = new JButton("Cancel"); + + private final int space = 5; + + private SettingsPanel settingsPanel; + + private static final Logger logger = EnvoyLog.getLogger(SettingsScreen.class.getSimpleName()); + + /** + * Initializes the settings screen. + * + * @since Envoy v0.1-alpha + */ + public SettingsScreen() { + logger.info("Currently selected theme: " + Settings.getInstance().getCurrentTheme()); + + Map> panels = new HashMap<>(); + panels.put("Color Themes", ThemeCustomizationPanel.class); + + setBounds(10, 10, 450, 650); + getContentPane().setLayout(new BorderLayout()); + { + // Content pane + GridBagLayout gbl_contentPanel = new GridBagLayout(); + + gbl_contentPanel.columnWidths = new int[] { 1, 1 }; + gbl_contentPanel.rowHeights = new int[] { 1 }; + gbl_contentPanel.columnWeights = new double[] { 0.05, 1.0 }; + gbl_contentPanel.rowWeights = new double[] { 1.0 }; + + getContentPane().add(contentPanel, BorderLayout.CENTER); + contentPanel.setLayout(gbl_contentPanel); + + options.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + options.addListSelectionListener((listSelectionEvent) -> { + if (!listSelectionEvent.getValueIsAdjusting()) { + // Get selected settings panel + final String option = options.getSelectedValue(); + logger.log(Level.FINEST, "Selected settings panel: " + option); + + // Remove previous settings panel + if (settingsPanel != null) + contentPanel.remove(settingsPanel); + + try { + settingsPanel = panels.get(option).getDeclaredConstructor().newInstance(); + + // Add selected settings panel + contentPanel.add(settingsPanel); + revalidate(); + repaint(); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException + | NoSuchMethodException | SecurityException e) { + e.printStackTrace(); + } + } + }); + options.setFont(new Font("Arial", Font.PLAIN, 14)); + + GridBagConstraints gbc_optionsList = new GridBagConstraints(); + gbc_optionsList.fill = GridBagConstraints.BOTH; + gbc_optionsList.gridx = 0; + gbc_optionsList.gridy = 0; + gbc_optionsList.anchor = GridBagConstraints.PAGE_START; + gbc_optionsList.insets = new Insets(space, space, space, space); + + panels.keySet().forEach(name -> optionsListModel.addElement(name)); + contentPanel.add(options, gbc_optionsList); + + // ButtonPane + GridBagLayout gbl_buttonPane = new GridBagLayout(); + gbl_buttonPane.columnWidths = new int[] { 100, 250, 100, 0 }; + gbl_buttonPane.rowHeights = new int[] { 25, 0 }; + gbl_buttonPane.columnWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE }; + gbl_buttonPane.rowWeights = new double[] { 0.0, Double.MIN_VALUE }; + + getContentPane().add(buttonPane, BorderLayout.SOUTH); + buttonPane.setLayout(gbl_buttonPane); + { + cancelButton.setActionCommand("Cancel"); + cancelButton.setBorderPainted(false); + GridBagConstraints gbc_cancelButton = new GridBagConstraints(); + gbc_cancelButton.anchor = GridBagConstraints.NORTHWEST; + gbc_cancelButton.insets = new Insets(space, space, space, space); + gbc_cancelButton.gridx = 0; + gbc_cancelButton.gridy = 0; + buttonPane.add(cancelButton, gbc_cancelButton); + + cancelButton.addActionListener((evt) -> { dispose(); }); + } + { + okButton.setActionCommand("OK"); + okButton.setBorderPainted(false); + GridBagConstraints gbc_okButton = new GridBagConstraints(); + gbc_okButton.anchor = GridBagConstraints.NORTHEAST; + gbc_okButton.fill = GridBagConstraints.EAST; + gbc_okButton.insets = new Insets(space, space, space, space); + gbc_okButton.gridx = 2; + gbc_okButton.gridy = 0; + buttonPane.add(okButton, gbc_okButton); + getRootPane().setDefaultButton(okButton); + + // Invoke settings panel action on button press + okButton.addActionListener((evt) -> { if (settingsPanel != null) settingsPanel.getOkButtonAction().actionPerformed(evt); }); + } + } + + // Apply current theme + applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + + // Respond to theme changes + EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme(((ThemeChangeEvent) evt).get())); + + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + setModal(true); + } + + private void applyTheme(Theme theme) { + // whole JDialog + setBackground(theme.getBackgroundColor()); + // contentPanel + contentPanel.setBackground(theme.getBackgroundColor()); + // buttonPane + buttonPane.setBackground(theme.getCellColor()); + // cancelButton + cancelButton.setBackground(theme.getInteractableBackgroundColor()); + cancelButton.setForeground(theme.getInteractableForegroundColor()); + // okButton + okButton.setBackground(theme.getInteractableBackgroundColor()); + okButton.setForeground(theme.getInteractableForegroundColor()); + // options + options.setSelectionForeground(theme.getUserNameColor()); + options.setSelectionBackground(theme.getSelectionColor()); + options.setForeground(theme.getUserNameColor()); + options.setBackground(theme.getCellColor()); + } +} diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java new file mode 100644 index 0000000..61e484b --- /dev/null +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -0,0 +1,252 @@ +package envoy.client.ui.settings; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JColorChooser; +import javax.swing.JComboBox; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextPane; + +import envoy.client.Settings; +import envoy.client.event.EventBus; +import envoy.client.event.ThemeChangeEvent; +import envoy.client.ui.Theme; +import envoy.client.util.EnvoyLog; + +/** + * Project: envoy-client
+ * File: ThemeCustomizationPanel.java
+ * Created: 20 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class ThemeCustomizationPanel extends SettingsPanel { + + private static final long serialVersionUID = -8697897390666456624L; + + private JPanel colorsPanel = new JPanel(); + private JButton createNewThemeButton = new JButton("Create New Theme"); + + private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]); + private JComboBox themes = new JComboBox<>(themeArray); + private Theme temporaryTheme, selectedTheme; + + private final int space = 5; + + private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class.getSimpleName()); + + /** + * Initializes a {@link ThemeCustomizationPanel} that enables the user to change + * the current {@link Theme} and create new themes as part of the + * {@link SettingsScreen}. + */ + public ThemeCustomizationPanel() { + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + + // Theme content + GridBagConstraints gbc_themeContent = new GridBagConstraints(); + gbc_themeContent.fill = GridBagConstraints.BOTH; + gbc_themeContent.gridx = 1; + gbc_themeContent.gridy = 0; + gbc_themeContent.anchor = GridBagConstraints.PAGE_START; + gbc_themeContent.insets = new Insets(space, space, space, space); + + GridBagLayout gbl_themeLayout = new GridBagLayout(); + + gbl_themeLayout.columnWidths = new int[] { 1, 1 }; + gbl_themeLayout.rowHeights = new int[] { 1, 1 }; + gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 }; + gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0 }; + + setLayout(gbl_themeLayout); + + themes.setSelectedItem(Settings.getInstance().getCurrentTheme()); + + themes.addItemListener(new ItemListener() { + + @Override + public void itemStateChanged(ItemEvent e) { + String selectedValue = (String) themes.getSelectedItem(); + logger.log(Level.FINEST, selectedValue); + selectedTheme = Settings.getInstance().getThemes().get(selectedValue); + } + }); + + GridBagConstraints gbc_themes = new GridBagConstraints(); + gbc_themes.fill = GridBagConstraints.HORIZONTAL; + gbc_themes.gridx = 0; + gbc_themes.gridy = 0; + gbc_themes.anchor = GridBagConstraints.NORTHWEST; + gbc_themes.insets = new Insets(space, space, space, space); + + add(themes, gbc_themes); + + colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); + colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + + Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + buildCustomizeElements(theme); + + GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); + gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; + gbc_colorsPanel.gridx = 0; + gbc_colorsPanel.gridy = 1; + gbc_colorsPanel.gridwidth = 2; + gbc_colorsPanel.anchor = GridBagConstraints.NORTHWEST; + gbc_colorsPanel.insets = new Insets(space, 0, 0, 0); + + add(colorsPanel, gbc_colorsPanel); + + createNewThemeButton.setEnabled(false); + createNewThemeButton.setBackground(theme.getInteractableBackgroundColor()); + createNewThemeButton.setForeground(theme.getInteractableForegroundColor()); + colorsPanel.setBackground(theme.getCellColor()); + + createNewThemeButton.addActionListener((evt) -> { + try { + String s = JOptionPane.showInputDialog("Enter a name for the new theme"); + logger.log(Level.FINEST, s); + Settings.getInstance() + .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(), + temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(), + temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), + temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor())); + themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); + themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName(); + + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + + createNewThemeButton.setEnabled(false); + themes.addItem(themeArray[themeArray.length - 1]); + + } catch (Exception e) { + logger.info("New theme couldn't be created! " + e); + e.printStackTrace(); + } + }); + + GridBagConstraints gbc_createNewTheme = new GridBagConstraints(); + gbc_createNewTheme.gridx = 0; + gbc_createNewTheme.gridy = 10; + + colorsPanel.add(createNewThemeButton, gbc_createNewTheme); + + // Apply current theme + applyTheme(theme); + + // Respond to theme changes + EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme(((ThemeChangeEvent) evt).get())); + } + + @Override + public ActionListener getOkButtonAction() { + return (evt) -> { + Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); + logger.log(Level.FINER, "Setting theme: " + selectedTheme.getThemeName()); + + final Theme currentTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + updateColorVariables(currentTheme); + EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); + + revalidate(); + repaint(); + }; + } + + private void applyTheme(Theme theme) { + // themeContent + setForeground(theme.getUserNameColor()); + setBackground(theme.getCellColor()); + + // themes + themes.setBackground(theme.getBackgroundColor()); + themes.setForeground(getInvertedColor(theme.getBackgroundColor())); + + createNewThemeButton.setBackground(theme.getInteractableBackgroundColor()); + createNewThemeButton.setForeground(theme.getInteractableForegroundColor()); + colorsPanel.setBackground(theme.getCellColor()); + } + + private void updateColorVariables(Theme theme) { + temporaryTheme = new Theme("temporaryTheme", theme); + + colorsPanel.removeAll(); + + buildCustomizeElements(theme); + + GridBagConstraints gbc_createNewTheme = new GridBagConstraints(); + gbc_createNewTheme.gridx = 0; + gbc_createNewTheme.gridy = 10; + + colorsPanel.add(createNewThemeButton, gbc_createNewTheme); + } + + private void buildCustomizeElements(Theme theme) { + buildCustomizeElement(theme, theme.getBackgroundColor(), "Background", "backgroundColor"); + buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor"); + buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor"); + buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor"); + buildCustomizeElement(theme, theme.getMessageColorChat(), "Messages Chat", "messageColorChat"); + buildCustomizeElement(theme, theme.getDateColorChat(), "Date Chat", "dateColorCat"); + buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor"); + buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor"); + buildCustomizeElement(theme, theme.getUserNameColor(), "User Names", "userNameColor"); + } + + private void buildCustomizeElement(Theme theme, Color color, String name, String colorName) { + JPanel panel = new JPanel(); + JButton button = new JButton(); + JTextPane textPane = new JTextPane(); + + textPane.setFont(new Font("Arial", Font.PLAIN, 14)); + textPane.setBackground(theme.getBackgroundColor()); + textPane.setForeground(getInvertedColor(theme.getBackgroundColor())); + textPane.setText(name); + textPane.setEditable(false); + + button.setBackground(color); + button.setPreferredSize(new Dimension(25, 25)); + + button.addActionListener((evt) -> { + try { + Color newColor = JColorChooser.showDialog(null, "Choose a color", color); + if (newColor.getRGB() != color.getRGB()) { + logger.log(Level.FINEST, "New Color: " + String.valueOf(color.getRGB())); + // TODO: When Theme changed in same settings screen, color variable doesn't + // update + temporaryTheme.setColor(colorName, newColor); + createNewThemeButton.setEnabled(true); + } + button.setBackground(newColor); + + } catch (Exception e) { + logger.info("An error occured while opening Color Chooser: " + e); + e.printStackTrace(); + } + }); + + panel.add(textPane); + panel.add(button); + panel.setBackground(theme.getCellColor()); + panel.setAlignmentX(Component.LEFT_ALIGNMENT); + + colorsPanel.add(panel); + } + + private Color getInvertedColor(Color color) { return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); } +} diff --git a/src/main/resources/envoy_logo_old.png b/src/main/resources/envoy_logo_old.png deleted file mode 100644 index 35ef7d9fd78cc3b79454de104ae59fbb65c0b050..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8152 zcmZ`;Wl$VluwC3eKwxnQ3jqSb-NNFo!5xCT%c3Dza0wC!5Fl7^*Wm7Mi~HhkZ@>5N z{dhGsb7y+0?^N}jbGy&!NL6JS987Xd004j^Co826AKT%lD>^FtdSYbvp8?rgLP-Ju zsEWgSGDU$u)0oSuD**t$i~vAT7y$49HwEnj03I9wz@Z5MAeasSkUD2Is|mwjpqeSj zNC95|J968KlHe9JcR3|6+7<>0A~~Jp-@a1-fNDifNZg|fCY399^zfQ}d{#?cv8~gqW@~xp0omJMFm(E(qt#%v>b2f- zi=m$7kvcagl)#Emf${-?5m7rAX91-ZSvWS{kFPApM`10?gF^|^ z2Xv-oLVkYg1v+CLpgt_|HMtzsu*~~wDx5_4RMRt+@zB(H8l<37RSayLSM53FV`Ikx zJqY%(Fn5W8t6ApJ!K7sB91^la;uayt2;W1$%-GxZKiPd~M!cg}bPUu3ig5q2+5^FfrdZngBsGWa{M`dp>^t~W*jdB# ziqhY5kmix#dHHVjP7Y^80(3#*`EqY{f)^5<@OxqD6lI1-1Xfo~!d3!;GRNChTGX3-gR(88*$r#Fj77J{O?+1GFdh4$i z%HKDUX&1h+tTfU4FwCC$k5Zwq<}p64<2gUF;ijHoD&lv$F=N4JMB(gxKLI_t>${K6 z6~zynXUo4Xlvu{LbJ9jkW>a>!DNgfz6_8Xqe7>2(f+-yWwaI&%aNm4<(yu`8I*!z3 z{UH_{?iPLa5K`uMf)9b5z75V5)jUrN5$V%%5^iL*+=+xQcm6=ri`=h;P(m>R zQm}*uu_ibdJs6qun4CCGWhYv}%DHj0pZ%peQ^%9Chy|ZqH3wfceJht^xr=$g|5Y&P zi4{0+U@+v7rdZGmgiem4-Svy=2oo0*HGUaJQaB_GP?4dBL#4~|)?QmPrm2}$42b@< z!>*>-MsH?23IA;J!l2z{)m{^P77_dC6xPc> zKVH4y(jX@!Y9xxP3tgUYt>~e~^C>xd?^`C7)|H@nQu11(?)ZHWY9)Ov9Ws|fP2m#(Cp_AOD(>QZj0{6Bq@dwt+%gE0O}H2{3S>hB zND3GSfX^?8Etc;G9WM8;B0d||C260Mu`%qG@XK zH4H*2jh37?8No*LL2P@H6gZCJgHqGNCs2j05DeZETb>4ksF#xV>p>w2)IPC+?YJY~ z)4HtG?#A}UKxGOrIP>MtYz9VjbA+Q{=*B1omSXnS7lMj_ITI&Adjwr=M5!xJ&!C zu?piIrYAC&(MG-c6Auiy=}&9*$gz)BIz0JCVO;vk>^!kNe!@?#F3hBF78WNtKL-q2 z52=uM@o|J8PA)#SfC}7dS7nOC2CfoWQ`wj-?~(L31^xM}DU$~k2H~72qV+CecfkiUu<#?>K!AJlj zW4y;W-~Fr1Qu2;k3)JPqrMv$2`gF^1{B5Nn>#?1^B-jXzdo2zbm8*#VKLTDB)HC<& zGyxyaLLu|R2Zzpm-3XWO@HG(Yy3zid(_L;DK#~E^8Vb8<>TPwwCj5OCaX}b0@=Te= z-)+@C3i`jLG^Y=XO|-&%K=6tWU8B)al#fd}snq-;^gF5_L5}{eX}GjjB*NhL=m%pl zkKHK&6bnJ_mwJcX!#q9Bp*lsE`>P$k{o_p=Y6Z|})73^6L5G7U_4-x_g>mj{HS%npdb*d7Cq2UDd2P(4EMthU7HQa1GJ#N8ZRqpT$l<9#e zLSM2ujD}d+?g)IQA4t~8M+PFvR<;E;n7_oo)qg5a81#g;hh)w(hAPH5b&Xf}EB3A= z(=yh8tlZ#b2pno)t#rY^Sy^U#LH=J`u*fJ@kIw1UrpnMuEj!P6kGe=g zUJ#TINh4Cu{`6f^C&k!x>9{-aI=`44Bw;eyd(%?ECGbh=tlVpL8B+T4Z@;ML&^M+EDQY8s|Iyjfvc?6a_bJ zO}n2FLB>edpPQ^TFm`!inFg{$JkVXt4b94OakzR)* zRi&?X96G;F%w0L$D7xE=cmNQThLy-rZ|Tj_etlPT`j0qROJjg_wBM|zXN2BQ@@=;H zaBcanCC;G>J|^qx=o)l;hkBWR~Pln*%}K_l5E9T)ypfyjmSI1HR6~anYOOD5O^CoeP}>)Hi(?EeQ~WG)y=(e% z;rsLs3sy1xR*?mfjlEu|s`O9xuAp0GR+3}yR`l|(j;Sig`$jx&o(hz8!2MO~Lg2g;5bA!}qveLH~xJ2J#TbD)>aJ*Y?rRzafme zu0mhbQ~J`n6OI;@Yc>f6FQf1>zbEXiFE7iCe7ai^ zJzTqsr!s#18L(DsK(6oa?v6Kc?g14Ohbdp}WU=(ML6I8gwRsV}m`bL8aBURGJJ+&E zsVw9Q7j-z=-}QaZ$hRuWFUT=)IdJo;IxWXLh+N{*(LyF2AF$RpRJ1M?`*l`X`d z3uLp=)KHhLhursHdO?(yD>8=M_J2>O59paa3thTqC;}h0AD_P$E!H}$B0SsuJUnlc zqRl8E@b_|fm$vd*j3#hoc{C7~l@_f9Md@_fkOp&pH;WY=-a>qOR6` zBq99~5exPVlbe6lpcroH4l@1EJhgcSSCz_JemLAPVgBL?q_W1mm<|UaNt)t(rjV&t zZ21c=)v$DiFxhZ?iodMo74tz;`&%c0*OXj9*Z=J$^!LHkC zxodm0BCS%bs!V*Tj*NxERtwdPvXqQc+q`xp$09ol=xmUUGnQA2dgc8*jX{@~(@b7^ z{bAjai94OsWYEy^7QX;1G%)(z<|f$;kH^IJ1($;)FRs2Ajt(ucr1KM97`J$j<{F;2 z@518dUZJk;)Bb87fq?Po9K5dK_gva(Yp3CqUf@FFpE~YcJ&gT9rR3wn$QNLS+3|FQ zcAh5)n(ZV>lsn_0XX-9t(axYXJuzZ0WoI!{ZqGKPujDVU_!HV(n9zpGydkR(`dRVo zQ`To56zi|qerd)7YH2wQN2sxvWa67-i>coO6QyT;HVVlIy`3trRvi%5gqKDsb(AT2 zGKHnKV3^QY`m2(X_?=45-yBIlek+rVv+pF4l3WfHB88z+-|=Edu*gYIp}%0fd>2p< z05ES<-L5J!k3pBB7r;jgi-g=cr(Fm>f6@*}0C2w=oF-0G{0}ni7{~Cyd z&WnE8X?tiq4_bpAd=!psZ+BCgDi#EMr8CyVRvV`QO4Z&;3b!@||Mf4)GK>)R_qK5N zUJv&O{ZyVUi=nO5Yo#UEpex&8SFp&P%+w%9i){Q^ICg{^tHaOKxD|Z@^=tr$_W^j~ zSw;Z*4(xm6vtyG3!L#-8Kv|Um zs2|@r<&fBQR=m~pfa~WfT}{n*?d#ALW`UJ}ZVD>Ds-F&zOIwx>5@)ldkU%Z`jfW~LotDi&DudhXDUaP>IsBW68=GR1HSkV1XH39t@`0{mm6`X{6E zVU>+#2->bi{cCY&FBs&N^Hc0tR|>t+!b)_#-39kAWTMaM=U;mK340X`k>e|9U&NGzUfBRSCxO3Ded*3)|`C|Rj#@~$=o=0E%-9ZNyv6%Ny zG4d7UGPHo|ISs{_d`5zi%N6gfpN}HEk58|wZZ;jzej-uL{q{bZ&G|s}%yKq{@ElE& zdhlpoqSbVzK94;KacM~|6Cy1#(Iw@I$Etmy(!lmF>zj)q7|FlpVA^+ZLhYsU*|y~3 zlXc+<1P6PZ<(6Fm!ylQsE3OMp<|_KJ+1K#22n_BM=-ORJ6*CM210SD6J$Zbkx3en7 z05XQ6G5kkPVI0Pt?8YL|kS1ReA)vvN$tW)QcMnt9NZNPJAN)>k95LKP>QZEg0>otK z<#>WUFoiK!WHtM9fr+C+->dT1Mo)4w`c#}=nNE+rs;m@{9^*Xw)VaP&$;(C0t380?@btXXIaFJ~SS-23=xakL^kc^rS#zGsW54tSc zR(0vsBvBmSX+z~3Zx0A_@HnaRQi%z6l>J`ov2opN1fdT*;QZ_YCW8}4d85>9G5fNu zNu@`$=;R3<9_QaJ^%p7stLMm{p_#&ovKW%E+)TS}Rk|o`(vcW%LfkmBI6(-U%w2dI z3O!~D3BWM$qt5B>eE)IRc@m;uQ-k=q$`sj#pi_(Ctl7r@z+4xLem%p@I(XH)JHCP~ z5j*UasGn9~Mrj6twMCNfuWUs5@s=RIV3(0Q{#a22lBVuBFZzU!u(;)wgnWnL%Ph6n z*j`T05p*t7(iPjdlOsCSL@Q>>2c~Arp&Tf(4;FCGOQd%H+u)_ntmnIY5>h&Lbk7+Q zZ^r1^fi0!r{I3cIm*Y$~I-K0;?yxHNHHU3WOyng{cZfLC_0q?}gwgI%e!xo+l3oMZ zLIpXMf!yD9Nui^ZGkjhbU8d}(e9ezHJAzsk9Jt7j;PZ`m$=!n>drP ztDg^w4fssBK)nPaw&CEy_e_#BfJg@Wpuf}OlX#iVlpen#l$WJ^(eGMmdq|u{hYIu^ zd`b$CA#Yiq))1+JYu{ju%7` zaxojn4fTDPCU0%a;t8KjU0)9Cwo$4tQ8on?fv*N5lsc^G+Q|TC3fg*oMiPSxiy{@$ zrGxU*$!@{bH5l|)Hro7ya66%i;I5Go$q3I?U@n0-)#nJ>!<8fLLdIg{;AChHBS`V* zJVd?=f7?3&33i^HW9lJP7f4!-WRVZ&w^ z9u$zL`eb>xi~{6WRu_-aU<#yjBB&=Sh8-bNWYdq{`2w@nCYSrGWRo1YC<`Ict-i^n z!#1Zqb1-2(=hG5G6h;@W{*~u%?@%U$Du?kRU}obGAdpxZtPmuZPGs)T`G{yV^=5c( zFI7ceiT}530v$N&4YPW||8v7&YQU~LP+r`O#1G;3c}J1<4NZiHC1TByp*P*yAc8c( zneyz1snvRZ=PM#}mkMGc=NJ2^H(Skc4HFl;zD6IE4~bZQLoZd0@nRIuN9gA_9G`cz z8tG^f<@Tu>BTzM$!hNhQXc1R(Wb~mD8r8>7lSsks?ZzadS30pD!JN;8Z(eQ#W$avS? zQz=JFg)}DQqo}=CR`w9SFzgk~9+dv=-poCJKqs5nu6?IMw+>4j{Ui9F9!=Zd#$41! z_6t^l1~E*8_IKfpY@3z(I4W}s9)Ig# zmb^ed`=q#W)aHe2g7IxHn`KTBPzkg}vYH7WxZvB<*1SDh1nV>-YD(`2SqxNS(Rf*= zY?c-4MIJ;vdYCX4cKfiC7xK-&$Nww9QUV*(RkQT8$_S+3BK%~r%7-D<6;ztC@+ReP z%d#pS!vk%WQet^Od+LB+HnA2`9Nhi57n2onS|I|V} zrK_fe;%-TXjMU5#%xyHE<8I3gKUSbU49;z-bRJhh-aLb#d9*{jh)zKU zs3T%(9|TiJtFtO%)@W)Vy|r(y6LHPdG+*rYU$HZ=yQG6wq7Ln$I#;9*AE5n+9|#if zJ6FXOq?(DnX{;@^2!fJ_u&_0C9Mioom)fbLICcSUbW{2g!U1DHWkY0nyTpi=7|Pt| z%a*n){;d45eF#Vw`Yoeg_LdH*6Q3K29sHZ!Q(Kb-@FT}Z+CNfVZIdfNmjn24nw^M0@V=8W!3c4a5Wx0DjYF%^=wBxh zrB-QQfM&e~(UVAe&NbO2giuXLYSHsHLqG4@$ZN(4Os7%-N$f+VE8`O9m33>8pk?pT zZ1Y`2HNz8^2G;=!rDoeyXwbq`=ZHnHrSPOc7JtjMN2kAacfNuPFrZulET#AZh|sBT zwWyyajYZMMX*U>_q4hE}xY(Bc)M1}P+ZsjkTW(T4;k_JG=-jvN;UFB)ix%Bsg@=yL z4dAolM$B4#p3Jvk2YjoAoiBbZs@OG$H%s!}x@y-lCMcks+d6d}?mutm(~FMshx9#; z_Ls)5SQG3;0_nU%Uf4%L*~GJ+(8F)$hU%3Sw-Mu18~_zfk?^lE1d&R46R*Pv6H&je zbSqd(s!$e)6O8EIY!PzwBeoUwYK|ttdrUbVJ^EKV;2{QAg2JfTVN?~5o%1#7F0lXv z6KhTIG>Yp|=OJ@{Od-Xf5X@uvF|f9*35-T{U>t+_fL0fPv)!0o8O6A$nQb50Dw;}3 z4H)G0a@a}GDB}`U_a?X?Q=Fz3FANgmUp#o*nPZmx1Uw5+&fwy~?|}bG0Uv2ne1S9^ zjI{UE56hQA!PcnSpt;Z|QBVgipY)S4VqA-zcJ_BnenvUoF7}9|_h4@IZ}Pdmce6OL zE%k`-c=|%^vSy0Xq%8iR8AX36+Fw%sg!78h_-^w|5{lEp;c2R8vWxgm4g7jMcKF26 zEQ-+2AdI!*vpLZ-V1?OLL+`VipPgLdhCAVLqC}(qmW%$SW6eyJHiAKan@j z`#<=147@dS!S9oEkZ`2FNlQGWxgHBW+{FS;60P;aMq2J&SkZT?sR>Ocf?zU zvrW`)X&0unVJlWIERwSAu}!>1X`h#^9T7!I&xO#Zh)NwX@URvrJ^1%4bniu7zWn`T zZ+(3Taf4-_Yv3ycVR85cL<+dneWK&@w$;WFSYEombAWG6b(DABJsY3+nm zrA1*dB#ULvf>w%B^^MD23oK(O2h{AamvO$fRm3l`JM=zy+xTM#Nt?H&ee_f#=-u7c zTX>||(vPm==TX^gH zojdrmyM?K{rJ%X1C42yIa(onE;}Bru Date: Sat, 21 Dec 2019 00:43:38 +0100 Subject: [PATCH 132/474] Added missing Javadoc since tags as requested by @delvh --- src/main/java/envoy/client/Config.java | 1 + src/main/java/envoy/client/event/MessageEvent.java | 1 + src/main/java/envoy/client/event/ThemeChangeEvent.java | 2 ++ src/main/java/envoy/client/ui/ChatWindow.java | 1 + src/main/java/envoy/client/ui/Startup.java | 1 + src/main/java/envoy/client/ui/Theme.java | 2 ++ 6 files changed, 8 insertions(+) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index e28dc92..ca86a33 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -31,6 +31,7 @@ public class Config { /** * @return the singleton instance of the {@link Config} + * @since Envoy v0.1-alpha */ public static Config getInstance() { if (config == null) config = new Config(); diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java index 8eb7384..2e818e5 100644 --- a/src/main/java/envoy/client/event/MessageEvent.java +++ b/src/main/java/envoy/client/event/MessageEvent.java @@ -18,6 +18,7 @@ public class MessageEvent implements Event { * {@link Message} object. * * @param message the {@link Message} object to attach to this event + * @since Envoy v0.2-alpha */ public MessageEvent(Message message) { this.message = message; } diff --git a/src/main/java/envoy/client/event/ThemeChangeEvent.java b/src/main/java/envoy/client/event/ThemeChangeEvent.java index 84e6218..ac07aa1 100644 --- a/src/main/java/envoy/client/event/ThemeChangeEvent.java +++ b/src/main/java/envoy/client/event/ThemeChangeEvent.java @@ -8,6 +8,7 @@ import envoy.client.ui.Theme; * Created: 15 Dec 2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public class ThemeChangeEvent implements Event { @@ -18,6 +19,7 @@ public class ThemeChangeEvent implements Event { * of the {@link Theme} currently in use * * @param theme the new currently used {@link Theme} object + * @since Envoy v0.2-alpha */ public ThemeChangeEvent(Theme theme) { this.theme = theme; } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index ea8ab1e..b21e2d9 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -72,6 +72,7 @@ public class ChatWindow extends JFrame { * * @param client the {@link Client} used to send and receive messages * @param localDB the {@link LocalDB} used to manage stored messages and users + * @since Envoy v0.1-alpha */ public ChatWindow(Client client, LocalDB localDB) { this.client = client; diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index b226911..df07361 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -41,6 +41,7 @@ public class Startup { * * @param args the command line arguments may contain configuration parameters * and are parsed by the {@link Config} class + * @since Envoy v0.1-alpha */ public static void main(String[] args) { Config config = Config.getInstance(); diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index 78eccc6..bd2ccb3 100644 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -41,6 +41,7 @@ public class Theme implements Serializable { * @param selectionColor the section color * @param typingMessageColor the color of currently typed messages * @param userNameColor the color of user names + * @since Envoy v0.2-alpha */ public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, Color interactableBackgroundColor, Color messageColorChat, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) { @@ -64,6 +65,7 @@ public class Theme implements Serializable { * * @param name the name of the {@link Theme} * @param other the {@link Theme} to copy + * @since Envoy v0.2-alpha */ public Theme(String name, Theme other) { this(name, other.backgroundColor, other.cellColor, other.interactableForegroundColor, From e367e5d57d88dbfbbf7e4d8eb8877a185aa99a7f Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 07:54:15 +0100 Subject: [PATCH 133/474] Added custom import organization preferences Imports are converted to .* after 4 imports from the same package, static imports are converted to .* after 2 imports from the same type --- .settings/org.eclipse.jdt.ui.prefs | 5 +++ src/main/java/envoy/client/Settings.java | 7 +---- src/main/java/envoy/client/ui/ChatWindow.java | 23 ++------------ .../client/ui/settings/SettingsScreen.java | 31 ++++++++----------- .../ui/settings/ThemeCustomizationPanel.java | 28 ++++------------- 5 files changed, 28 insertions(+), 66 deletions(-) create mode 100644 .settings/org.eclipse.jdt.ui.prefs diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000..cdb456a --- /dev/null +++ b/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=java;javax;org;com; +org.eclipse.jdt.ui.ondemandthreshold=4 +org.eclipse.jdt.ui.staticondemandthreshold=2 diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 75a4355..d7e01de 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -1,12 +1,7 @@ package envoy.client; import java.awt.Color; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; +import java.io.*; import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 8b1c60c..50b40bc 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,32 +1,15 @@ package envoy.client.ui; -import java.awt.ComponentOrientation; -import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.Toolkit; +import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.DefaultListModel; -import javax.swing.JFrame; -import javax.swing.JList; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextPane; -import javax.swing.ListSelectionModel; -import javax.swing.SwingUtilities; -import javax.swing.Timer; +import javax.swing.*; import javax.swing.border.EmptyBorder; -import envoy.client.Chat; -import envoy.client.Client; -import envoy.client.Config; -import envoy.client.LocalDB; -import envoy.client.Settings; +import envoy.client.*; import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.settings.SettingsScreen; diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index d34eee4..65cacac 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -1,22 +1,13 @@ package envoy.client.ui.settings; -import java.awt.BorderLayout; -import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; +import java.awt.*; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.DefaultListModel; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.ListSelectionModel; +import javax.swing.*; import envoy.client.Settings; import envoy.client.event.EventBus; @@ -50,7 +41,7 @@ public class SettingsScreen extends JDialog { private final JButton okButton = new JButton("Save"); private final JButton cancelButton = new JButton("Cancel"); - private final int space = 5; + private final Insets insets = new Insets(5, 5, 5, 5); private SettingsPanel settingsPanel; @@ -62,8 +53,7 @@ public class SettingsScreen extends JDialog { * @since Envoy v0.1-alpha */ public SettingsScreen() { - logger.info("Currently selected theme: " + Settings.getInstance().getCurrentTheme()); - + // Initialize settings pages Map> panels = new HashMap<>(); panels.put("Color Themes", ThemeCustomizationPanel.class); @@ -112,7 +102,7 @@ public class SettingsScreen extends JDialog { gbc_optionsList.gridx = 0; gbc_optionsList.gridy = 0; gbc_optionsList.anchor = GridBagConstraints.PAGE_START; - gbc_optionsList.insets = new Insets(space, space, space, space); + gbc_optionsList.insets = insets; panels.keySet().forEach(name -> optionsListModel.addElement(name)); contentPanel.add(options, gbc_optionsList); @@ -131,7 +121,7 @@ public class SettingsScreen extends JDialog { cancelButton.setBorderPainted(false); GridBagConstraints gbc_cancelButton = new GridBagConstraints(); gbc_cancelButton.anchor = GridBagConstraints.NORTHWEST; - gbc_cancelButton.insets = new Insets(space, space, space, space); + gbc_cancelButton.insets = insets; gbc_cancelButton.gridx = 0; gbc_cancelButton.gridy = 0; buttonPane.add(cancelButton, gbc_cancelButton); @@ -144,7 +134,7 @@ public class SettingsScreen extends JDialog { GridBagConstraints gbc_okButton = new GridBagConstraints(); gbc_okButton.anchor = GridBagConstraints.NORTHEAST; gbc_okButton.fill = GridBagConstraints.EAST; - gbc_okButton.insets = new Insets(space, space, space, space); + gbc_okButton.insets = insets; gbc_okButton.gridx = 2; gbc_okButton.gridy = 0; buttonPane.add(okButton, gbc_okButton); @@ -166,18 +156,23 @@ public class SettingsScreen extends JDialog { } private void applyTheme(Theme theme) { - // whole JDialog + // JDialog setBackground(theme.getBackgroundColor()); + // contentPanel contentPanel.setBackground(theme.getBackgroundColor()); + // buttonPane buttonPane.setBackground(theme.getCellColor()); + // cancelButton cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor()); + // okButton okButton.setBackground(theme.getInteractableBackgroundColor()); okButton.setForeground(theme.getInteractableForegroundColor()); + // options options.setSelectionForeground(theme.getUserNameColor()); options.setSelectionBackground(theme.getSelectionColor()); diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 61e484b..ed9c5db 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -1,12 +1,6 @@ package envoy.client.ui.settings; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; +import java.awt.*; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; @@ -14,13 +8,7 @@ import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JColorChooser; -import javax.swing.JComboBox; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextPane; +import javax.swing.*; import envoy.client.Settings; import envoy.client.event.EventBus; @@ -119,15 +107,11 @@ public class ThemeCustomizationPanel extends SettingsPanel { createNewThemeButton.addActionListener((evt) -> { try { - String s = JOptionPane.showInputDialog("Enter a name for the new theme"); - logger.log(Level.FINEST, s); - Settings.getInstance() - .addNewThemeToMap(new Theme(s, temporaryTheme.getBackgroundColor(), temporaryTheme.getCellColor(), - temporaryTheme.getInteractableForegroundColor(), temporaryTheme.getInteractableBackgroundColor(), - temporaryTheme.getMessageColorChat(), temporaryTheme.getDateColorChat(), temporaryTheme.getSelectionColor(), - temporaryTheme.getTypingMessageColor(), temporaryTheme.getUserNameColor())); + String name = JOptionPane.showInputDialog("Enter a name for the new theme"); + logger.log(Level.FINEST, name); + Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); - themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(s).getThemeName(); + themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(name).getThemeName(); temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); From 5c93255fb6002e336e978a183c8a0ff095a4f28c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 08:06:05 +0100 Subject: [PATCH 134/474] Fixed layout of SettingsPanel in SettingsScreen --- .../envoy/client/ui/settings/SettingsScreen.java | 12 ++++++++++-- .../ui/settings/ThemeCustomizationPanel.java | 14 +++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 65cacac..740750d 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -60,7 +60,7 @@ public class SettingsScreen extends JDialog { setBounds(10, 10, 450, 650); getContentPane().setLayout(new BorderLayout()); { - // Content pane + // ContentPane GridBagLayout gbl_contentPanel = new GridBagLayout(); gbl_contentPanel.columnWidths = new int[] { 1, 1 }; @@ -71,6 +71,14 @@ public class SettingsScreen extends JDialog { getContentPane().add(contentPanel, BorderLayout.CENTER); contentPanel.setLayout(gbl_contentPanel); + // Constraints for the settings panel + GridBagConstraints gbc_panel = new GridBagConstraints(); + gbc_panel.fill = GridBagConstraints.BOTH; + gbc_panel.gridx = 1; + gbc_panel.gridy = 0; + gbc_panel.anchor = GridBagConstraints.PAGE_START; + gbc_panel.insets = insets; + options.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); options.addListSelectionListener((listSelectionEvent) -> { if (!listSelectionEvent.getValueIsAdjusting()) { @@ -86,7 +94,7 @@ public class SettingsScreen extends JDialog { settingsPanel = panels.get(option).getDeclaredConstructor().newInstance(); // Add selected settings panel - contentPanel.add(settingsPanel); + contentPanel.add(settingsPanel, gbc_panel); revalidate(); repaint(); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index ed9c5db..57780f3 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -34,7 +34,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { private JComboBox themes = new JComboBox<>(themeArray); private Theme temporaryTheme, selectedTheme; - private final int space = 5; + private final Insets insets = new Insets(5, 5, 5, 5); private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class.getSimpleName()); @@ -46,14 +46,6 @@ public class ThemeCustomizationPanel extends SettingsPanel { public ThemeCustomizationPanel() { temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); - // Theme content - GridBagConstraints gbc_themeContent = new GridBagConstraints(); - gbc_themeContent.fill = GridBagConstraints.BOTH; - gbc_themeContent.gridx = 1; - gbc_themeContent.gridy = 0; - gbc_themeContent.anchor = GridBagConstraints.PAGE_START; - gbc_themeContent.insets = new Insets(space, space, space, space); - GridBagLayout gbl_themeLayout = new GridBagLayout(); gbl_themeLayout.columnWidths = new int[] { 1, 1 }; @@ -80,7 +72,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { gbc_themes.gridx = 0; gbc_themes.gridy = 0; gbc_themes.anchor = GridBagConstraints.NORTHWEST; - gbc_themes.insets = new Insets(space, space, space, space); + gbc_themes.insets = insets; add(themes, gbc_themes); @@ -96,7 +88,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { gbc_colorsPanel.gridy = 1; gbc_colorsPanel.gridwidth = 2; gbc_colorsPanel.anchor = GridBagConstraints.NORTHWEST; - gbc_colorsPanel.insets = new Insets(space, 0, 0, 0); + gbc_colorsPanel.insets = insets; add(colorsPanel, gbc_colorsPanel); From cd508af2d9f8b0cc49d91558d9a5dee9466630a3 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 10:02:25 +0100 Subject: [PATCH 135/474] Added Javadoc since tags as requested by @delvh --- src/main/java/envoy/client/ui/Theme.java | 3 +++ src/main/java/envoy/client/ui/settings/SettingsPanel.java | 6 ++++++ src/main/java/envoy/client/ui/settings/SettingsScreen.java | 6 +++--- .../envoy/client/ui/settings/ThemeCustomizationPanel.java | 6 ++++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index c498655..3e6c39e 100644 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -35,6 +35,7 @@ public class Theme implements Serializable { * @param selectionColor the section color * @param typingMessageColor the color of currently typed messages * @param userNameColor the color of user names + * @since Envoy v0.2-alpha */ public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, Color interactableBackgroundColor, Color messageColorChat, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) { @@ -58,6 +59,7 @@ public class Theme implements Serializable { * * @param name the name of the {@link Theme} * @param other the {@link Theme} to copy + * @since Envoy v0.2-alpha */ public Theme(String name, Theme other) { themeName = name; @@ -67,6 +69,7 @@ public class Theme implements Serializable { /** * @return a {@code Map} of all colors defined for this theme * with their names as keys + * @since Envoy v0.2-alpha */ public Map getColors() { return colors; } diff --git a/src/main/java/envoy/client/ui/settings/SettingsPanel.java b/src/main/java/envoy/client/ui/settings/SettingsPanel.java index 56e1957..9b8f239 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/SettingsPanel.java @@ -5,11 +5,16 @@ import java.awt.event.ActionListener; import javax.swing.JPanel; /** + * Serves as an interface between {@link SettingsScreen} and different + * {@link JPanel}s with actual settings that are defined as sub classes of this + * class.
+ *
* Project: envoy-client
* File: SettingsPanel.java
* Created: 20 Dec 2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public abstract class SettingsPanel extends JPanel { @@ -18,6 +23,7 @@ public abstract class SettingsPanel extends JPanel { /** * @return an {@link ActionListener} that should be invoked when the OK button * is pressed in the {@link SettingsScreen} + * @since Envoy v0.2-alpha */ public abstract ActionListener getOkButtonAction(); } diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 740750d..d283d6b 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -25,6 +25,7 @@ import envoy.client.util.EnvoyLog; * @author Leon Hofmeister * @author Maximilian Käfer * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public class SettingsScreen extends JDialog { @@ -87,8 +88,7 @@ public class SettingsScreen extends JDialog { logger.log(Level.FINEST, "Selected settings panel: " + option); // Remove previous settings panel - if (settingsPanel != null) - contentPanel.remove(settingsPanel); + if (settingsPanel != null) contentPanel.remove(settingsPanel); try { settingsPanel = panels.get(option).getDeclaredConstructor().newInstance(); @@ -99,7 +99,7 @@ public class SettingsScreen extends JDialog { repaint(); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { - e.printStackTrace(); + logger.log(Level.SEVERE, "Failed to invoke constructor of SettingsPanel " + option, e); } } }); diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 57780f3..6a1aa66 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -17,11 +17,15 @@ import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; /** + * Displays GUI components that allow changing the current {@Theme} and creating + * new ones.
+ *
* Project: envoy-client
* File: ThemeCustomizationPanel.java
* Created: 20 Dec 2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public class ThemeCustomizationPanel extends SettingsPanel { @@ -42,6 +46,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { * Initializes a {@link ThemeCustomizationPanel} that enables the user to change * the current {@link Theme} and create new themes as part of the * {@link SettingsScreen}. + * + * @since Envoy v0.2-alpha */ public ThemeCustomizationPanel() { temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); From f31f25261387ce3db51fef185b1f1e19feee5472 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 21 Dec 2019 11:17:23 +0100 Subject: [PATCH 136/474] Fixed UI Alignment of theme customization components Fixes #39 --- .../ui/settings/ThemeCustomizationPanel.java | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 6a1aa66..755b5b1 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -82,9 +82,19 @@ public class ThemeCustomizationPanel extends SettingsPanel { add(themes, gbc_themes); - colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); - colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); +// colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); +// colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + + GridBagLayout gbl_colorCustomizations = new GridBagLayout(); + gbl_colorCustomizations.columnWidths = new int[] { 1, 1 }; + gbl_colorCustomizations.rowHeights = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1}; + gbl_colorCustomizations.columnWeights = new double[] { 1.0, 1.0 }; + gbl_colorCustomizations.rowWeights = new double[] { 1, 1, 1, 1, 1, 1, 1, 1}; + + colorsPanel.setLayout(gbl_colorCustomizations); + + Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); buildCustomizeElements(theme); @@ -170,6 +180,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.removeAll(); buildCustomizeElements(theme); + colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); GridBagConstraints gbc_createNewTheme = new GridBagConstraints(); gbc_createNewTheme.gridx = 0; @@ -179,19 +190,18 @@ public class ThemeCustomizationPanel extends SettingsPanel { } private void buildCustomizeElements(Theme theme) { - buildCustomizeElement(theme, theme.getBackgroundColor(), "Background", "backgroundColor"); - buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor"); - buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor"); - buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor"); - buildCustomizeElement(theme, theme.getMessageColorChat(), "Messages Chat", "messageColorChat"); - buildCustomizeElement(theme, theme.getDateColorChat(), "Date Chat", "dateColorCat"); - buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor"); - buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor"); - buildCustomizeElement(theme, theme.getUserNameColor(), "User Names", "userNameColor"); + buildCustomizeElement(theme, theme.getBackgroundColor(), "Background", "backgroundColor", 1); + buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor", 2); + buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3); + buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor", 4); + buildCustomizeElement(theme, theme.getMessageColorChat(), "Messages Chat", "messageColorChat", 5); + buildCustomizeElement(theme, theme.getDateColorChat(), "Date Chat", "dateColorCat", 6); + buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor", 7); + buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor", 8); + buildCustomizeElement(theme, theme.getUserNameColor(), "User Names", "userNameColor", 9); } - private void buildCustomizeElement(Theme theme, Color color, String name, String colorName) { - JPanel panel = new JPanel(); + private void buildCustomizeElement(Theme theme, Color color, String name, String colorName, int gridy) { JButton button = new JButton(); JTextPane textPane = new JTextPane(); @@ -222,12 +232,24 @@ public class ThemeCustomizationPanel extends SettingsPanel { } }); - panel.add(textPane); - panel.add(button); - panel.setBackground(theme.getCellColor()); - panel.setAlignmentX(Component.LEFT_ALIGNMENT); + GridBagConstraints gbc_textPane = new GridBagConstraints(); + gbc_textPane.fill = GridBagConstraints.BOTH; + gbc_textPane.gridx = 0; + gbc_textPane.gridy = gridy; + gbc_textPane.anchor = GridBagConstraints.CENTER; + gbc_textPane.insets = insets; - colorsPanel.add(panel); + colorsPanel.add(textPane, gbc_textPane); + + + GridBagConstraints gbc_button = new GridBagConstraints(); + gbc_button.fill = GridBagConstraints.BOTH; + gbc_button.gridx = 1; + gbc_button.gridy = gridy; + gbc_button.anchor = GridBagConstraints.CENTER; + gbc_button.insets = insets; + + colorsPanel.add(button, gbc_button); } private Color getInvertedColor(Color color) { return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); } From c2f7bd7b219f1f28232e6ffa57baedfa03685cdb Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 11:35:01 +0100 Subject: [PATCH 137/474] Improved Config machanism with ConfigItems Added logger levels and home directory to Config --- src/main/java/envoy/client/Config.java | 102 +++++++----------- src/main/java/envoy/client/ConfigItem.java | 32 ++++++ src/main/java/envoy/client/ui/Startup.java | 3 + src/main/java/envoy/client/util/EnvoyLog.java | 34 +++--- 4 files changed, 94 insertions(+), 77 deletions(-) create mode 100644 src/main/java/envoy/client/ConfigItem.java diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index ca86a33..b1388ae 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -1,7 +1,10 @@ package envoy.client; import java.io.File; +import java.util.HashMap; +import java.util.Map; import java.util.Properties; +import java.util.logging.Level; import envoy.exception.EnvoyException; @@ -20,14 +23,19 @@ import envoy.exception.EnvoyException; */ public class Config { - private String server; - private int port; - private File localDB; - private int syncTimeout; + private Map> items = new HashMap<>(); private static Config config; - private Config() {} + private Config() { + items.put("server", new ConfigItem<>("server", "s", (input) -> input, null)); + items.put("port", new ConfigItem<>("port", "p", (input) -> Integer.parseInt(input), null)); + items.put("localDB", new ConfigItem<>("localDB", "db", (input) -> new File(input), new File("localDB"))); + items.put("syncTimeout", new ConfigItem<>("syncTimeout", "st", (input) -> Integer.parseInt(input), 1000)); + items.put("homeDirectory", new ConfigItem<>("homeDirectory", "h", (input) -> new File(input), new File(System.getProperty("user.home")))); + items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", (input) -> Level.parse(input), Level.CONFIG)); + items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", (input) -> Level.parse(input), Level.FINEST)); + } /** * @return the singleton instance of the {@link Config} @@ -53,10 +61,7 @@ public class Config { try { Properties properties = new Properties(); properties.load(loader.getResourceAsStream("client.properties")); - if (properties.containsKey("server")) server = properties.getProperty("server"); - if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); - localDB = new File(properties.getProperty("localDB", ".\\localDB")); - syncTimeout = Integer.parseInt(properties.getProperty("syncTimeout", "1000")); + items.forEach((name, item) -> { if (properties.containsKey(name)) item.parse(properties.getProperty(name)); }); } catch (Exception e) { throw new EnvoyException("Failed to load client.properties", e); } @@ -72,84 +77,57 @@ public class Config { */ public void load(String[] args) throws EnvoyException { for (int i = 0; i < args.length; i++) - switch (args[i]) { - case "--server": - case "-s": - server = args[++i]; - break; - case "--port": - case "-p": - port = Integer.parseInt(args[++i]); - break; - case "--localDB": - case "-db": - localDB = new File(args[++i]); - break; - default: - throw new EnvoyException("Unknown token " + args[i] + " found"); - } + for (ConfigItem item : items.values()) + if (args[i].startsWith("--")) { + if (args[i].length() == 2) throw new EnvoyException("Malformed command line argument at position " + i); + final String commandLong = args[i].substring(2); + if (item.getCommandLong().equals(commandLong)) { + item.parse(args[++i]); + break; + } + } else if (args[i].startsWith("-")) { + if (args[i].length() == 1) throw new EnvoyException("Malformed command line argument at position " + i); + final String commandShort = args[i].substring(1); + if (item.getCommandShort().equals(commandShort)) { + item.parse(args[++i]); + break; + } + } else throw new EnvoyException("Malformed command line argument at position " + i); } /** * @return {@code true} if server, port and localDB directory are known. * @since Envoy v0.1-alpha */ - public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; } + public boolean isInitialized() { return items.values().stream().noneMatch(item -> item.get() == null); } /** * @return the host name of the Envoy server * @since Envoy v0.1-alpha */ - public String getServer() { return server; } - - /** - * Changes the default server host name. - * Exclusively intended for development purposes. - * - * @param server the host name of the Envoy server - * @since Envoy v0.1-alpha - */ - public void setServer(String server) { this.server = server; } + public String getServer() { return (String) items.get("server").get(); } /** * @return the port at which the Envoy server is located on the host * @since Envoy v0.1-alpha */ - public int getPort() { return port; } - - /** - * Changes the default port. - * Exclusively intended for development purposes. - * - * @param port the port where an Envoy server is located - * @since Envoy v0.1-alpha - */ - public void setPort(int port) { this.port = port; } + public int getPort() { return (int) items.get("port").get(); } /** * @return the local database specific to the client user * @since Envoy v0.1-alpha **/ - public File getLocalDB() { return localDB; } - - /** - * Changes the default local database. - * Exclusively intended for development purposes. - * - * @param localDB the file containing the local database - * @since Envoy v0.1-alpha - **/ - public void setLocalDB(File localDB) { this.localDB = localDB; } + public File getLocalDB() { return (File) items.get("localDB").get(); } /** * @return the current time (milliseconds) that is waited between Syncs * @since Envoy v0.1-alpha */ - public int getSyncTimeout() { return syncTimeout; } + public int getSyncTimeout() { return (int) items.get("syncTimeout").get(); } - /** - * @param syncTimeout sets the time (milliseconds) during which Sync waits - * @since Envoy v0.1-alpha - */ - public void setSyncTimeout(int syncTimeout) { this.syncTimeout = syncTimeout; } + public File getHomeDirectory() { return (File) items.get("homeDirectory").get(); } + + public Level getFileLevelBarrier() { return (Level) items.get("fileLevelBarrier").get(); } + + public Level getConsoleLevelBarrier() { return (Level) items.get("consoleLevelBarrier").get(); } } diff --git a/src/main/java/envoy/client/ConfigItem.java b/src/main/java/envoy/client/ConfigItem.java new file mode 100644 index 0000000..fb30e10 --- /dev/null +++ b/src/main/java/envoy/client/ConfigItem.java @@ -0,0 +1,32 @@ +package envoy.client; + +import java.util.function.Function; + +/** + * Project: envoy-clientChess
+ * File: ConfigItem.javaEvent.java
+ * Created: 21.12.2019
+ * + * @author Kai S. K. Engelbart + */ +public class ConfigItem { + + private String commandLong, commandShort; + private Function parseFunction; + private T value; + + public ConfigItem(String commandLong, String commandShort, Function parseFunction, T defaultValue) { + this.commandLong = commandLong; + this.commandShort = commandShort; + this.parseFunction = parseFunction; + value = defaultValue; + } + + public void parse(String input) { value = parseFunction.apply(input); } + + public String getCommandLong() { return commandLong; } + + public String getCommandShort() { return commandShort; } + + public T get() { return value; } +} diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index df07361..f1d75bb 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -61,6 +61,9 @@ public class Startup { System.exit(1); e.printStackTrace(); } + + EnvoyLog.setFileLevelBarrier(Config.getInstance().getFileLevelBarrier()); + EnvoyLog.setConsoleLevelBarrier(Config.getInstance().getConsoleLevelBarrier()); // Ask the user for their user name String userName = JOptionPane.showInputDialog("Please enter your username"); diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index db4e03c..f844aae 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -2,11 +2,9 @@ package envoy.client.util; import java.io.File; import java.io.IOException; -import java.util.logging.ConsoleHandler; -import java.util.logging.FileHandler; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.logging.SimpleFormatter; +import java.util.logging.*; + +import envoy.client.Config; /** * Project: envoy-client
@@ -14,28 +12,30 @@ import java.util.logging.SimpleFormatter; * Created: 14 Dec 2019
* * @author Leon Hofmeister + * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha */ public class EnvoyLog { - private static Level fileLevelBarrier = Level.CONFIG; + private static Level fileLevelBarrier = Config.getInstance().getFileLevelBarrier(), consoleLevelBarrier = Config.getInstance().getConsoleLevelBarrier(); private EnvoyLog() {} /** * Creates a {@link Logger} with a specified name + * * @param name the name of the {@link Logger} to create * @return the created {@link Logger} */ public static Logger getLogger(String name) { // Get a logger with the specified name Logger logger = Logger.getLogger(name); - + final String logPath = "log/envoy_user.log"; new File(logPath).getParentFile().mkdirs(); - - SimpleFormatter formatter = new SimpleFormatter(); - + + SimpleFormatter formatter = new SimpleFormatter(); + try { FileHandler fh = new FileHandler(logPath); fh.setLevel(fileLevelBarrier); @@ -44,15 +44,15 @@ public class EnvoyLog { } catch (SecurityException | IOException e) { e.printStackTrace(); } - + ConsoleHandler ch = new ConsoleHandler(); - ch.setLevel(Level.FINEST); + ch.setLevel(consoleLevelBarrier); ch.setFormatter(formatter); logger.addHandler(ch); - + return logger; } - + /** * @return the fileLevelBarrier: The current barrier for writing logs to a file. * @since Envoy v0.2-alpha @@ -66,5 +66,9 @@ public class EnvoyLog { * from 0 - 1000 or with the according name of the level * @since Envoy v0.2-alpha */ - public static void setFileLevel(String fileLevelBarrier) { EnvoyLog.fileLevelBarrier = Level.parse(fileLevelBarrier); } + public static void setFileLevelBarrier(Level fileLevelBarrier) { EnvoyLog.fileLevelBarrier = fileLevelBarrier; } + + public static Level getConsoleLevelBarrier() { return consoleLevelBarrier; } + + public static void setConsoleLevelBarrier(Level consoleLevelBarrier) { EnvoyLog.consoleLevelBarrier = consoleLevelBarrier; } } From 921f1f868982a0d293224f0377114583e1bf96f6 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 11:50:01 +0100 Subject: [PATCH 138/474] Moved local files to .envoy directory in user home Fixes #57 --- .gitignore | 5 +---- src/main/java/envoy/client/Config.java | 2 +- src/main/java/envoy/client/Settings.java | 2 +- src/main/java/envoy/client/ui/Startup.java | 12 +++++------- src/main/java/envoy/client/util/EnvoyLog.java | 2 +- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index d77958c..a6f89c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ -/target/ -/localDB/ -/log/ -/themes.ser \ No newline at end of file +/target/ \ No newline at end of file diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index b1388ae..b479de8 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -32,7 +32,7 @@ public class Config { items.put("port", new ConfigItem<>("port", "p", (input) -> Integer.parseInt(input), null)); items.put("localDB", new ConfigItem<>("localDB", "db", (input) -> new File(input), new File("localDB"))); items.put("syncTimeout", new ConfigItem<>("syncTimeout", "st", (input) -> Integer.parseInt(input), 1000)); - items.put("homeDirectory", new ConfigItem<>("homeDirectory", "h", (input) -> new File(input), new File(System.getProperty("user.home")))); + items.put("homeDirectory", new ConfigItem<>("homeDirectory", "h", (input) -> new File(input), new File(System.getProperty("user.home"), ".envoy"))); items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", (input) -> Level.parse(input), Level.CONFIG)); items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", (input) -> Level.parse(input), Level.FINEST)); } diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index d7e01de..6502049 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -37,7 +37,7 @@ public class Settings { /** * User-defined themes are stored inside this file. */ - private File themeFile = new File("themes.ser"); + private File themeFile = new File(Config.getInstance().getHomeDirectory(), "themes.ser"); /** * Singleton instance of this class. diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index f1d75bb..11db9f6 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -1,6 +1,7 @@ package envoy.client.ui; import java.awt.EventQueue; +import java.io.File; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -8,10 +9,7 @@ import java.util.logging.Logger; import javax.swing.JFrame; import javax.swing.JOptionPane; -import envoy.client.Client; -import envoy.client.Config; -import envoy.client.LocalDB; -import envoy.client.Settings; +import envoy.client.*; import envoy.client.util.EnvoyLog; import envoy.exception.EnvoyException; import envoy.schema.User; @@ -62,8 +60,8 @@ public class Startup { e.printStackTrace(); } - EnvoyLog.setFileLevelBarrier(Config.getInstance().getFileLevelBarrier()); - EnvoyLog.setConsoleLevelBarrier(Config.getInstance().getConsoleLevelBarrier()); + EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); + EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); // Ask the user for their user name String userName = JOptionPane.showInputDialog("Please enter your username"); @@ -75,7 +73,7 @@ public class Startup { // Initialize the local database LocalDB localDB; try { - localDB = new LocalDB(config.getLocalDB()); + localDB = new LocalDB(new File(config.getHomeDirectory(), config.getLocalDB().getPath())); } catch (IOException e3) { logger.log(Level.SEVERE, "Could not initialize local database", e3); JOptionPane.showMessageDialog(null, "Could not initialize local database!\n" + e3.toString()); diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index f844aae..1e93b4c 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -31,7 +31,7 @@ public class EnvoyLog { // Get a logger with the specified name Logger logger = Logger.getLogger(name); - final String logPath = "log/envoy_user.log"; + final String logPath = new File(Config.getInstance().getHomeDirectory(), "log/envoy_user.log").getAbsolutePath(); new File(logPath).getParentFile().mkdirs(); SimpleFormatter formatter = new SimpleFormatter(); From 57ffbc2b2c27c37b403c456dc994afb46be887d6 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 12:20:23 +0100 Subject: [PATCH 139/474] Implemented logger level configuration, added Javadoc Fixes #45 --- src/main/java/envoy/client/Config.java | 12 ++++ src/main/java/envoy/client/ConfigItem.java | 32 +++++++++ src/main/java/envoy/client/ui/Startup.java | 1 + src/main/java/envoy/client/util/EnvoyLog.java | 67 ++++++++++--------- 4 files changed, 81 insertions(+), 31 deletions(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index b479de8..14dc6f6 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -125,9 +125,21 @@ public class Config { */ public int getSyncTimeout() { return (int) items.get("syncTimeout").get(); } + /** + * @return the directory in which all local files are saves + * @since Envoy v0.2-alpha + */ public File getHomeDirectory() { return (File) items.get("homeDirectory").get(); } + /** + * @return the minimal {@link Level} to log inside the log file + * @since Envoy v0.2-alpha + */ public Level getFileLevelBarrier() { return (Level) items.get("fileLevelBarrier").get(); } + /** + * @return the minimal {@link Level} to log inside the console + * @since Envoy v0.2-alpha + */ public Level getConsoleLevelBarrier() { return (Level) items.get("consoleLevelBarrier").get(); } } diff --git a/src/main/java/envoy/client/ConfigItem.java b/src/main/java/envoy/client/ConfigItem.java index fb30e10..87e927b 100644 --- a/src/main/java/envoy/client/ConfigItem.java +++ b/src/main/java/envoy/client/ConfigItem.java @@ -3,11 +3,16 @@ package envoy.client; import java.util.function.Function; /** + * Contains a single {@link Config} value as well as the corresponding command + * line arguments and its default value.
+ *
* Project: envoy-clientChess
* File: ConfigItem.javaEvent.java
* Created: 21.12.2019
* * @author Kai S. K. Engelbart + * @param the type of the config item's value + * @since Envoy v0.2-alpha */ public class ConfigItem { @@ -15,6 +20,16 @@ public class ConfigItem { private Function parseFunction; private T value; + /** + * Initializes a {@link ConfigItem} + * + * @param commandLong the long command line argument to set this value + * @param commandShort the short command line argument to set this value + * @param parseFunction the {@code Function} that parses the value + * from a string + * @param defaultValue the optional default value to set before parsing + * @since Envoy v0.2-alpha + */ public ConfigItem(String commandLong, String commandShort, Function parseFunction, T defaultValue) { this.commandLong = commandLong; this.commandShort = commandShort; @@ -22,11 +37,28 @@ public class ConfigItem { value = defaultValue; } + /** + * Parses this {@ConfigItem}'s value from a string + * @param input the string to parse from + * @since Envoy v0.2-alpha + */ public void parse(String input) { value = parseFunction.apply(input); } + /** + * @return The long command line argument to set the value of this {@link ConfigItem} + * @since Envoy v0.2-alpha + */ public String getCommandLong() { return commandLong; } + /** + * @return The short command line argument to set the value of this {@link ConfigItem} + * @since Envoy v0.2-alpha + */ public String getCommandShort() { return commandShort; } + /** + * @return the value of this {@link ConfigItem} + * @since Envoy v0.2-alpha + */ public T get() { return value; } } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 11db9f6..21e4cf0 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -60,6 +60,7 @@ public class Startup { e.printStackTrace(); } + // Set new logger levels loaded from config EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index 1e93b4c..ab2012d 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -17,7 +17,25 @@ import envoy.client.Config; */ public class EnvoyLog { - private static Level fileLevelBarrier = Config.getInstance().getFileLevelBarrier(), consoleLevelBarrier = Config.getInstance().getConsoleLevelBarrier(); + private static FileHandler fileHandler; + private static ConsoleHandler consoleHandler; + + static { + File logFile = new File(Config.getInstance().getHomeDirectory(), "log/envoy_user.log"); + logFile.getParentFile().mkdirs(); + SimpleFormatter formatter = new SimpleFormatter(); + + try { + fileHandler = new FileHandler(logFile.getAbsolutePath()); + fileHandler.setLevel(Config.getInstance().getFileLevelBarrier()); + fileHandler.setFormatter(formatter); + } catch (SecurityException | IOException e) { + e.printStackTrace(); + } + consoleHandler = new ConsoleHandler(); + consoleHandler.setLevel(Config.getInstance().getConsoleLevelBarrier()); + consoleHandler.setFormatter(formatter); + } private EnvoyLog() {} @@ -31,44 +49,31 @@ public class EnvoyLog { // Get a logger with the specified name Logger logger = Logger.getLogger(name); - final String logPath = new File(Config.getInstance().getHomeDirectory(), "log/envoy_user.log").getAbsolutePath(); - new File(logPath).getParentFile().mkdirs(); - - SimpleFormatter formatter = new SimpleFormatter(); - - try { - FileHandler fh = new FileHandler(logPath); - fh.setLevel(fileLevelBarrier); - fh.setFormatter(formatter); - logger.addHandler(fh); - } catch (SecurityException | IOException e) { - e.printStackTrace(); - } - - ConsoleHandler ch = new ConsoleHandler(); - ch.setLevel(consoleLevelBarrier); - ch.setFormatter(formatter); - logger.addHandler(ch); + // Add handlers + if (fileHandler != null) logger.addHandler(fileHandler); + if (consoleHandler != null) logger.addHandler(consoleHandler); return logger; } /** - * @return the fileLevelBarrier: The current barrier for writing logs to a file. - * @since Envoy v0.2-alpha - */ - public static Level getFileLevelBarrier() { return fileLevelBarrier; } - - /** - * @param fileLevelBarrier the severity below which logRecords will be written - * only to the console. At or above they'll also be + * @param fileLevelBarrier the severity below which logRecords will not be + * written to the log file. At or above they'll also be * logged in a file. Can be written either in Digits * from 0 - 1000 or with the according name of the level * @since Envoy v0.2-alpha */ - public static void setFileLevelBarrier(Level fileLevelBarrier) { EnvoyLog.fileLevelBarrier = fileLevelBarrier; } + public static void setFileLevelBarrier(Level fileLevelBarrier) { if (fileHandler != null) fileHandler.setLevel(fileLevelBarrier); } - public static Level getConsoleLevelBarrier() { return consoleLevelBarrier; } - - public static void setConsoleLevelBarrier(Level consoleLevelBarrier) { EnvoyLog.consoleLevelBarrier = consoleLevelBarrier; } + /** + * @param consoleLevelBarrier the severity below which logRecords will not be + * written to the console. At or above they'll also + * be logged in a file. Can be written either in + * digits from 0 - 1000 or with the according name of + * the level + * @since Envoy v0.2-alpha + */ + public static void setConsoleLevelBarrier(Level consoleLevelBarrier) { + if (consoleHandler != null) consoleHandler.setLevel(consoleLevelBarrier); + } } From b1dbe58f2c96499659ae12834ed1709ef3c7be46 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 21 Dec 2019 12:24:11 +0100 Subject: [PATCH 140/474] User Friendly Settings * Removed CreateNewButton button and added it's functionality to the save button. * Revised theme dropDown style. fixes #64 --- .../ui/settings/ThemeCustomizationPanel.java | 160 ++++++++---------- 1 file changed, 73 insertions(+), 87 deletions(-) diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 755b5b1..ad7fe5a 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -31,12 +31,12 @@ public class ThemeCustomizationPanel extends SettingsPanel { private static final long serialVersionUID = -8697897390666456624L; - private JPanel colorsPanel = new JPanel(); - private JButton createNewThemeButton = new JButton("Create New Theme"); + private JPanel colorsPanel = new JPanel(); - private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]); - private JComboBox themes = new JComboBox<>(themeArray); - private Theme temporaryTheme, selectedTheme; + private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]); + private JComboBox themes = new JComboBox<>(themeArray); + private Theme temporaryTheme, selectedTheme; + private boolean themeChanged = false; private final Insets insets = new Insets(5, 5, 5, 5); @@ -50,14 +50,15 @@ public class ThemeCustomizationPanel extends SettingsPanel { * @since Envoy v0.2-alpha */ public ThemeCustomizationPanel() { - temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); GridBagLayout gbl_themeLayout = new GridBagLayout(); - gbl_themeLayout.columnWidths = new int[] { 1, 1 }; - gbl_themeLayout.rowHeights = new int[] { 1, 1 }; - gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 }; - gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0 }; + gbl_themeLayout.columnWidths = new int[] { 1, 1 }; + gbl_themeLayout.rowHeights = new int[] { 1, 1 }; + gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 }; + gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0 }; setLayout(gbl_themeLayout); @@ -74,70 +75,41 @@ public class ThemeCustomizationPanel extends SettingsPanel { }); GridBagConstraints gbc_themes = new GridBagConstraints(); - gbc_themes.fill = GridBagConstraints.HORIZONTAL; - gbc_themes.gridx = 0; - gbc_themes.gridy = 0; - gbc_themes.anchor = GridBagConstraints.NORTHWEST; - gbc_themes.insets = insets; + gbc_themes.fill = GridBagConstraints.HORIZONTAL; + gbc_themes.gridwidth = 2; + gbc_themes.gridx = 0; + gbc_themes.gridy = 0; + gbc_themes.anchor = GridBagConstraints.NORTHWEST; + gbc_themes.insets = new Insets(10, 10, 20, 10); add(themes, gbc_themes); // colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); // colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - + GridBagLayout gbl_colorCustomizations = new GridBagLayout(); - gbl_colorCustomizations.columnWidths = new int[] { 1, 1 }; - gbl_colorCustomizations.rowHeights = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1}; - gbl_colorCustomizations.columnWeights = new double[] { 1.0, 1.0 }; - gbl_colorCustomizations.rowWeights = new double[] { 1, 1, 1, 1, 1, 1, 1, 1}; + gbl_colorCustomizations.columnWidths = new int[] { 1, 1 }; + gbl_colorCustomizations.rowHeights = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + gbl_colorCustomizations.columnWeights = new double[] { 1, 1 }; + gbl_colorCustomizations.rowWeights = new double[] { 1, 1, 1, 1, 1, 1, 1, 1 }; colorsPanel.setLayout(gbl_colorCustomizations); - - + Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); buildCustomizeElements(theme); GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); - gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; - gbc_colorsPanel.gridx = 0; - gbc_colorsPanel.gridy = 1; - gbc_colorsPanel.gridwidth = 2; - gbc_colorsPanel.anchor = GridBagConstraints.NORTHWEST; - gbc_colorsPanel.insets = insets; + gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; + gbc_colorsPanel.gridx = 0; + gbc_colorsPanel.gridy = 1; + gbc_colorsPanel.gridwidth = 2; + gbc_colorsPanel.anchor = GridBagConstraints.NORTHWEST; + gbc_colorsPanel.insets = insets; add(colorsPanel, gbc_colorsPanel); - - createNewThemeButton.setEnabled(false); - createNewThemeButton.setBackground(theme.getInteractableBackgroundColor()); - createNewThemeButton.setForeground(theme.getInteractableForegroundColor()); colorsPanel.setBackground(theme.getCellColor()); - createNewThemeButton.addActionListener((evt) -> { - try { - String name = JOptionPane.showInputDialog("Enter a name for the new theme"); - logger.log(Level.FINEST, name); - Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); - themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); - themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(name).getThemeName(); - - temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); - - createNewThemeButton.setEnabled(false); - themes.addItem(themeArray[themeArray.length - 1]); - - } catch (Exception e) { - logger.info("New theme couldn't be created! " + e); - e.printStackTrace(); - } - }); - - GridBagConstraints gbc_createNewTheme = new GridBagConstraints(); - gbc_createNewTheme.gridx = 0; - gbc_createNewTheme.gridy = 10; - - colorsPanel.add(createNewThemeButton, gbc_createNewTheme); - // Apply current theme applyTheme(theme); @@ -148,6 +120,27 @@ public class ThemeCustomizationPanel extends SettingsPanel { @Override public ActionListener getOkButtonAction() { return (evt) -> { + if (themeChanged) { + try { + String name = JOptionPane.showInputDialog("Enter a name for the new theme"); + logger.log(Level.FINEST, name); + Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); + themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); + themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(name).getThemeName(); + + temporaryTheme = new Theme("temporaryTheme", + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + + themes.addItem(themeArray[themeArray.length - 1]); + themes.setSelectedIndex(themeArray.length - 1); + + } catch (Exception e) { + logger.info("New theme couldn't be created! " + e); + e.printStackTrace(); + } + themeChanged = false; + } + Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); logger.log(Level.FINER, "Setting theme: " + selectedTheme.getThemeName()); @@ -166,11 +159,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { setBackground(theme.getCellColor()); // themes - themes.setBackground(theme.getBackgroundColor()); - themes.setForeground(getInvertedColor(theme.getBackgroundColor())); - - createNewThemeButton.setBackground(theme.getInteractableBackgroundColor()); - createNewThemeButton.setForeground(theme.getInteractableForegroundColor()); + themes.setBackground(theme.getInteractableBackgroundColor()); + themes.setForeground(theme.getInteractableForegroundColor()); colorsPanel.setBackground(theme.getCellColor()); } @@ -180,20 +170,15 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.removeAll(); buildCustomizeElements(theme); - colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); - - GridBagConstraints gbc_createNewTheme = new GridBagConstraints(); - gbc_createNewTheme.gridx = 0; - gbc_createNewTheme.gridy = 10; - - colorsPanel.add(createNewThemeButton, gbc_createNewTheme); } private void buildCustomizeElements(Theme theme) { buildCustomizeElement(theme, theme.getBackgroundColor(), "Background", "backgroundColor", 1); buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor", 2); - buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3); - buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor", 4); + buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", + "interactableForegroundColor", 3); + buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", + "interactableBackgroundColor", 4); buildCustomizeElement(theme, theme.getMessageColorChat(), "Messages Chat", "messageColorChat", 5); buildCustomizeElement(theme, theme.getDateColorChat(), "Date Chat", "dateColorCat", 6); buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor", 7); @@ -202,8 +187,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { } private void buildCustomizeElement(Theme theme, Color color, String name, String colorName, int gridy) { - JButton button = new JButton(); - JTextPane textPane = new JTextPane(); + JButton button = new JButton(); + JTextPane textPane = new JTextPane(); textPane.setFont(new Font("Arial", Font.PLAIN, 14)); textPane.setBackground(theme.getBackgroundColor()); @@ -222,7 +207,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { // TODO: When Theme changed in same settings screen, color variable doesn't // update temporaryTheme.setColor(colorName, newColor); - createNewThemeButton.setEnabled(true); + themeChanged = true; } button.setBackground(newColor); @@ -233,24 +218,25 @@ public class ThemeCustomizationPanel extends SettingsPanel { }); GridBagConstraints gbc_textPane = new GridBagConstraints(); - gbc_textPane.fill = GridBagConstraints.BOTH; - gbc_textPane.gridx = 0; - gbc_textPane.gridy = gridy; - gbc_textPane.anchor = GridBagConstraints.CENTER; - gbc_textPane.insets = insets; + gbc_textPane.fill = GridBagConstraints.BOTH; + gbc_textPane.gridx = 0; + gbc_textPane.gridy = gridy; + gbc_textPane.anchor = GridBagConstraints.CENTER; + gbc_textPane.insets = insets; colorsPanel.add(textPane, gbc_textPane); - - + GridBagConstraints gbc_button = new GridBagConstraints(); - gbc_button.fill = GridBagConstraints.BOTH; - gbc_button.gridx = 1; - gbc_button.gridy = gridy; - gbc_button.anchor = GridBagConstraints.CENTER; - gbc_button.insets = insets; + gbc_button.fill = GridBagConstraints.BOTH; + gbc_button.gridx = 1; + gbc_button.gridy = gridy; + gbc_button.anchor = GridBagConstraints.CENTER; + gbc_button.insets = insets; colorsPanel.add(button, gbc_button); } - private Color getInvertedColor(Color color) { return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); } + private Color getInvertedColor(Color color) { + return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); + } } From f22f0a766bd7aec2e65a3d8e446b88b4840fe18e Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 21 Dec 2019 12:31:32 +0100 Subject: [PATCH 141/474] Revising Added Author Removed Comments --- .../envoy/client/ui/settings/ThemeCustomizationPanel.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 755b5b1..abd70a8 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -25,6 +25,7 @@ import envoy.client.util.EnvoyLog; * Created: 20 Dec 2019
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy v0.2-alpha */ public class ThemeCustomizationPanel extends SettingsPanel { @@ -81,9 +82,6 @@ public class ThemeCustomizationPanel extends SettingsPanel { gbc_themes.insets = insets; add(themes, gbc_themes); - -// colorsPanel.setLayout(new BoxLayout(colorsPanel, BoxLayout.Y_AXIS)); -// colorsPanel.setAlignmentX(Component.LEFT_ALIGNMENT); GridBagLayout gbl_colorCustomizations = new GridBagLayout(); From 0393a0af8198ecc70551977c452e97761f449dce Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 12:36:26 +0100 Subject: [PATCH 142/474] Fixed Javadoc as requested by @delvh --- src/main/java/envoy/client/Config.java | 2 +- src/main/java/envoy/client/util/EnvoyLog.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 14dc6f6..3e511f9 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -116,7 +116,7 @@ public class Config { /** * @return the local database specific to the client user * @since Envoy v0.1-alpha - **/ + */ public File getLocalDB() { return (File) items.get("localDB").get(); } /** diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index ab2012d..282e1b4 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -44,6 +44,7 @@ public class EnvoyLog { * * @param name the name of the {@link Logger} to create * @return the created {@link Logger} + * @since Envoy v0.2-alpha */ public static Logger getLogger(String name) { // Get a logger with the specified name From 7c4129614969514de2bb6c037662ceaf7ebfa2d1 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 21 Dec 2019 13:18:20 +0100 Subject: [PATCH 143/474] Adjustment * Adjusted standard dark theme * Changed Save and Cancel buttons to PrimaryButtons --- src/main/java/envoy/client/Settings.java | 4 ++-- src/main/java/envoy/client/ui/settings/SettingsScreen.java | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 6502049..b1c0b6b 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -77,8 +77,8 @@ public class Settings { // Load standard themes not defined in the themes file themes.put("dark", - new Theme("dark", Color.black, Color.darkGray, Color.white, Color.blue, Color.white, Color.orange, Color.blue, Color.white, - Color.white)); + new Theme("dark", Color.black, Color.darkGray, Color.white, new Color(165, 60, 232), Color.white, Color.orange, Color.blue, + Color.white, Color.white)); themes.put("light", new Theme("light", new Color(235, 235, 235), Color.white, Color.white, Color.darkGray, Color.black, Color.orange, Color.darkGray, Color.black, Color.black)); diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index d283d6b..6655767 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -12,6 +12,7 @@ import javax.swing.*; import envoy.client.Settings; import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; +import envoy.client.ui.PrimaryButton; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; @@ -39,8 +40,8 @@ public class SettingsScreen extends JDialog { // OK and cancel buttons private final JPanel buttonPane = new JPanel(); - private final JButton okButton = new JButton("Save"); - private final JButton cancelButton = new JButton("Cancel"); + private final PrimaryButton okButton = new PrimaryButton("Save"); + private final PrimaryButton cancelButton = new PrimaryButton("Cancel"); private final Insets insets = new Insets(5, 5, 5, 5); From 2e033a4e84857f2560bdc7e31506663fc279075d Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 21 Dec 2019 18:05:31 +0100 Subject: [PATCH 144/474] Revised Cancel and Save Buttons * Fixed weird gbl_buttonPane declaration. * Added correct resizing and repositioning of cancel and save buttons when resizing the settings window. * Fixed incorrect buttonName displaying. --- .../java/envoy/client/ui/settings/SettingsScreen.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 6655767..29bbe92 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -118,10 +118,10 @@ public class SettingsScreen extends JDialog { // ButtonPane GridBagLayout gbl_buttonPane = new GridBagLayout(); - gbl_buttonPane.columnWidths = new int[] { 100, 250, 100, 0 }; - gbl_buttonPane.rowHeights = new int[] { 25, 0 }; - gbl_buttonPane.columnWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE }; - gbl_buttonPane.rowWeights = new double[] { 0.0, Double.MIN_VALUE }; + gbl_buttonPane.columnWidths = new int[] { 1, 1}; + gbl_buttonPane.rowHeights = new int[] { 25}; + gbl_buttonPane.columnWeights = new double[] { 1.0, 1.0}; + gbl_buttonPane.rowWeights = new double[] { 0.0}; getContentPane().add(buttonPane, BorderLayout.SOUTH); buttonPane.setLayout(gbl_buttonPane); From ab13d5adb42b155521d0abb926d545f6e0fccaa0 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 18:19:10 +0100 Subject: [PATCH 145/474] Improved logging Logs are now written to System.out instead of System.err. Also they are not duplicated as the default ConsoleHandler has been removed. When using the application, logs may not appear in the console immediately as the StreamHandler used to output them used an internal buffer that may only be flushed when closing the application. Logs are now formatted as [DATE TIME] [LEVEL] [LOGGER] MSG --- src/main/java/envoy/client/Config.java | 7 ++++--- src/main/java/envoy/client/ui/Startup.java | 2 +- src/main/java/envoy/client/util/EnvoyLog.java | 15 +++++++++++---- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 3e511f9..17da0d8 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -32,7 +32,8 @@ public class Config { items.put("port", new ConfigItem<>("port", "p", (input) -> Integer.parseInt(input), null)); items.put("localDB", new ConfigItem<>("localDB", "db", (input) -> new File(input), new File("localDB"))); items.put("syncTimeout", new ConfigItem<>("syncTimeout", "st", (input) -> Integer.parseInt(input), 1000)); - items.put("homeDirectory", new ConfigItem<>("homeDirectory", "h", (input) -> new File(input), new File(System.getProperty("user.home"), ".envoy"))); + items.put("homeDirectory", + new ConfigItem<>("homeDirectory", "h", (input) -> new File(input), new File(System.getProperty("user.home"), ".envoy"))); items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", (input) -> Level.parse(input), Level.CONFIG)); items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", (input) -> Level.parse(input), Level.FINEST)); } @@ -130,13 +131,13 @@ public class Config { * @since Envoy v0.2-alpha */ public File getHomeDirectory() { return (File) items.get("homeDirectory").get(); } - + /** * @return the minimal {@link Level} to log inside the log file * @since Envoy v0.2-alpha */ public Level getFileLevelBarrier() { return (Level) items.get("fileLevelBarrier").get(); } - + /** * @return the minimal {@link Level} to log inside the console * @since Envoy v0.2-alpha diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 21e4cf0..db9644a 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -59,7 +59,7 @@ public class Startup { System.exit(1); e.printStackTrace(); } - + // Set new logger levels loaded from config EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index 282e1b4..b59b714 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -10,7 +10,7 @@ import envoy.client.Config; * Project: envoy-client
* File: EnvoyLogger.java
* Created: 14 Dec 2019
- * + * * @author Leon Hofmeister * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha @@ -18,11 +18,18 @@ import envoy.client.Config; public class EnvoyLog { private static FileHandler fileHandler; - private static ConsoleHandler consoleHandler; + private static StreamHandler consoleHandler; static { + // Remove default console handler + LogManager.getLogManager().reset(); + + // Configure log file File logFile = new File(Config.getInstance().getHomeDirectory(), "log/envoy_user.log"); logFile.getParentFile().mkdirs(); + + // Configure formatting + System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT] [%4$-7s] [%3$s] %5$s %n"); SimpleFormatter formatter = new SimpleFormatter(); try { @@ -32,7 +39,7 @@ public class EnvoyLog { } catch (SecurityException | IOException e) { e.printStackTrace(); } - consoleHandler = new ConsoleHandler(); + consoleHandler = new StreamHandler(System.out, formatter); consoleHandler.setLevel(Config.getInstance().getConsoleLevelBarrier()); consoleHandler.setFormatter(formatter); } @@ -41,7 +48,7 @@ public class EnvoyLog { /** * Creates a {@link Logger} with a specified name - * + * * @param name the name of the {@link Logger} to create * @return the created {@link Logger} * @since Envoy v0.2-alpha From 5f3fce1f71052fbae0f56b68cf04492fddabeffd Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 18:29:59 +0100 Subject: [PATCH 146/474] Removed unnecessary log message from LocalDB, logging Sync --- src/main/java/envoy/client/Client.java | 23 +++++++++++++++-------- src/main/java/envoy/client/LocalDB.java | 21 ++++----------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index be0dd89..cfc894a 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,7 +1,9 @@ package envoy.client; +import java.io.StringWriter; import java.util.HashMap; import java.util.Map; +import java.util.logging.Logger; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; @@ -11,6 +13,7 @@ import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; +import envoy.client.util.EnvoyLog; import envoy.exception.EnvoyException; import envoy.schema.ObjectFactory; import envoy.schema.Sync; @@ -20,7 +23,7 @@ import envoy.schema.User; * Project: envoy-client
* File: Client.java
* Created: 28 Sep 2019
- * + * * @author Kai S. K. Engelbart * @author Maximilian Käfer * @author Leon Hofmeister @@ -33,10 +36,12 @@ public class Client { private User sender, recipient; private boolean online = false; + private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); + /** * Initializes the client. At this state, the client user has yet to be * initialized, which can be done by calling {@link Client#onlineInit(String)}. - * + * * @param config The {@link Config} instance to use in this client * @since Envoy v0.2-alpha */ @@ -44,7 +49,7 @@ public class Client { /** * Enters the online mode by acquiring a user ID from the server. - * + * * @param userName the name of the client user * @throws EnvoyException if the online mode could not be entered or the request * failed for some other reason @@ -88,7 +93,7 @@ public class Client { /** * Returns a {@link User} with a specific id by name. - * + * * @param name - the name of the {@link User} * @return a {@link User} with the specified name * @throws EnvoyException if the server does not return the requested ID @@ -146,7 +151,7 @@ public class Client { * Users:
* Updating UserStatus of all users in LocalDB. (Server sends all users with * their updated UserStatus to the client.)
- * + * * @param userId the id of the {@link Client} who sends the {@link Sync} * @param sync the sync object (yet to be converted from java class to * sync.xml) @@ -163,7 +168,9 @@ public class Client { jc = JAXBContext.newInstance("envoy.schema"); Marshaller m = jc.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - m.marshal(sync, System.out); + StringWriter stringWriter = new StringWriter(); + m.marshal(sync, stringWriter); + logger.fine("Sending sync:\n" + stringWriter.toString()); } catch (JAXBException e) { e.printStackTrace(); } @@ -180,7 +187,7 @@ public class Client { /** * Sets the client user which is used to send messages. - * + * * @param sender the client user to set * @since Envoy v0.2-alpha */ @@ -194,7 +201,7 @@ public class Client { /** * Sets the recipient. - * + * * @param recipient the recipient to set * @since Envoy v0.1-alpha */ diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 8c6a40b..dcc8b12 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -1,16 +1,8 @@ package envoy.client; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; +import java.io.*; import java.time.Instant; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.logging.Logger; import javax.xml.datatype.DatatypeConfigurationException; @@ -20,11 +12,8 @@ import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; import envoy.client.util.EnvoyLog; import envoy.exception.EnvoyException; -import envoy.schema.Message; +import envoy.schema.*; import envoy.schema.Message.Metadata.MessageState; -import envoy.schema.ObjectFactory; -import envoy.schema.Sync; -import envoy.schema.User; /** * Project: envoy-client
@@ -249,10 +238,8 @@ public class LocalDB { // Updating UserStatus of all users in LocalDB for (User user : returnSync.getUsers()) for (Chat chat : getChats()) - if (user.getID() == chat.getRecipient().getID()) { + if (user.getID() == chat.getRecipient().getID()) chat.getRecipient().setStatus(user.getStatus()); - logger.info(chat.getRecipient().getStatus().toString()); - } sync.getMessages().clear(); sync.getUsers().clear(); From 675488beb87d32cf1b2efbf95193703e2beb3b1c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 19:00:29 +0100 Subject: [PATCH 147/474] Loading ChatWindow in parallel to Client and LocalDB Fixes #26 --- src/main/java/envoy/client/ui/ChatWindow.java | 44 ++++++++++++------- src/main/java/envoy/client/ui/Startup.java | 15 ++++++- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index eb8ae44..4aae96a 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -54,14 +54,9 @@ public class ChatWindow extends JFrame { * Initializes a {@link JFrame} with UI elements used to send and read messages * to different users. * - * @param client the {@link Client} used to send and receive messages - * @param localDB the {@link LocalDB} used to manage stored messages and users * @since Envoy v0.1-alpha */ - public ChatWindow(Client client, LocalDB localDB) { - this.client = client; - this.localDB = localDB; - + public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); setTitle("Envoy"); @@ -164,7 +159,7 @@ public class ChatWindow extends JFrame { userList.setCellRenderer(new UserListRenderer()); userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); userList.addListSelectionListener((listSelectionEvent) -> { - if (!listSelectionEvent.getValueIsAdjusting()) { + if (client != null && localDB != null && !listSelectionEvent.getValueIsAdjusting()) { @SuppressWarnings("unchecked") final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); @@ -193,16 +188,12 @@ public class ChatWindow extends JFrame { gbc_userList.anchor = GridBagConstraints.PAGE_START; gbc_userList.insets = new Insets(space, space, space, space); - changeChatWindowColors(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); contentPane.add(userList, gbc_userList); contentPane.revalidate(); - EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> changeChatWindowColors((Theme) evt.get())); - - loadUsersAndChats(); - - if (client.isOnline()) startSyncThread(Config.getInstance().getSyncTimeout()); + EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get())); contentPane.revalidate(); } @@ -211,9 +202,9 @@ public class ChatWindow extends JFrame { * Used to immediately reload the ChatWindow when settings were changed. * * @param theme the theme to change colors into - * @since Envoy v0.1-alpha + * @since Envoy v0.2-alpha */ - private void changeChatWindowColors(Theme theme) { + private void applyTheme(Theme theme) { // contentPane contentPane.setBackground(theme.getBackgroundColor()); contentPane.setForeground(theme.getUserNameColor()); @@ -334,4 +325,27 @@ public class ChatWindow extends JFrame { * Marks messages in the current chat as {@code READ}. */ private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } + + /** + * Sets the {@link Client} used by this {@link ChatWindow}. If the client is + * online, the sync thread is started. + * + * @param client the {@link Client} used to send and receive messages + */ + public void setClient(Client client) { + this.client = client; + if (client.isOnline() && localDB != null) startSyncThread(Config.getInstance().getSyncTimeout()); + } + + /** + * Sets the {@link LocalDB} used by this {@link ChatWindow}. After invoking this + * method, users and chats will be loaded from the database into the GUI. + * + * @param localDB the {@link LocalDB} used to manage stored messages and users + */ + public void setLocalDB(LocalDB localDB) { + this.localDB = localDB; + loadUsersAndChats(); + if (client != null && client.isOnline()) startSyncThread(Config.getInstance().getSyncTimeout()); + } } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index db9644a..d4d4a78 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -8,6 +8,7 @@ import java.util.logging.Logger; import javax.swing.JFrame; import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; import envoy.client.*; import envoy.client.util.EnvoyLog; @@ -28,6 +29,8 @@ import envoy.schema.User; */ public class Startup { + private static ChatWindow chatWindow; + private static final Logger logger = EnvoyLog.getLogger(Startup.class.getSimpleName()); /** @@ -44,6 +47,8 @@ public class Startup { public static void main(String[] args) { Config config = Config.getInstance(); + SwingUtilities.invokeLater(() -> chatWindow = new ChatWindow()); + try { // Load the configuration from client.properties first config.load(); @@ -82,6 +87,8 @@ public class Startup { return; } + SwingUtilities.invokeLater(() -> chatWindow.setVisible(true)); + // Acquire the client user (with ID) either from the server or from the local // database, which triggers offline mode Client client = new Client(config); @@ -96,6 +103,10 @@ public class Startup { User clientUser = localDB.getUsers().get(userName); if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); client.setSender(clientUser); + JOptionPane.showMessageDialog(null, + "A connection to the server could not be established. Starting in offline mode.", + "Connection error", + JOptionPane.WARNING_MESSAGE); } catch (Exception e2) { JOptionPane.showMessageDialog(null, e2.toString(), "Client error", JOptionPane.ERROR_MESSAGE); System.exit(1); @@ -125,8 +136,8 @@ public class Startup { EventQueue.invokeLater(() -> { try { - ChatWindow chatWindow = new ChatWindow(client, localDB); - chatWindow.setVisible(true); + chatWindow.setClient(client); + chatWindow.setLocalDB(localDB); try { new StatusTrayIcon(chatWindow).show(); From d449192d172e007a306d81db6363587345b39d84 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 21:07:18 +0100 Subject: [PATCH 148/474] Added missing since tags as requested by @delvh --- src/main/java/envoy/client/ui/ChatWindow.java | 2 ++ src/main/java/envoy/client/ui/Startup.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 4aae96a..dc68e10 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -331,6 +331,7 @@ public class ChatWindow extends JFrame { * online, the sync thread is started. * * @param client the {@link Client} used to send and receive messages + * @since Envoy v0.2-alpha */ public void setClient(Client client) { this.client = client; @@ -342,6 +343,7 @@ public class ChatWindow extends JFrame { * method, users and chats will be loaded from the database into the GUI. * * @param localDB the {@link LocalDB} used to manage stored messages and users + * @since Envoy v0.2-alpha */ public void setLocalDB(LocalDB localDB) { this.localDB = localDB; diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index d4d4a78..ca68618 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -16,7 +16,7 @@ import envoy.exception.EnvoyException; import envoy.schema.User; /** - * Starts the Envoy client and prompts the user to enter their name. + * Starts the Envoy client and prompts the user to enter their name.
*
* Project: envoy-client
* File: Startup.java
From 70d2ef65381f953d252b83b30a25265d625dfc58 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Dec 2019 22:28:22 +0100 Subject: [PATCH 149/474] Delete SettingsScreen.java --- .../java/envoy/client/ui/SettingsScreen.java | 156 ------------------ 1 file changed, 156 deletions(-) delete mode 100644 src/main/java/envoy/client/ui/SettingsScreen.java diff --git a/src/main/java/envoy/client/ui/SettingsScreen.java b/src/main/java/envoy/client/ui/SettingsScreen.java deleted file mode 100644 index 7d5de28..0000000 --- a/src/main/java/envoy/client/ui/SettingsScreen.java +++ /dev/null @@ -1,156 +0,0 @@ -package envoy.client.ui; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.FlowLayout; - -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JPanel; -import javax.swing.border.EmptyBorder; - -/** - * Project: envoy-client
- * File: SettingsScreen.java
- * Created: 31 Oct 2019
- * - * @author Leon Hofmeister - */ -public class SettingsScreen extends JDialog { - - private static final long serialVersionUID = -4476913491263077107L; - private final JPanel contentPanel = new JPanel(); - public static boolean enterToSend = true; - - // TODO: Add a JPanel with all the Information necessary: - // change (Picture,Username, Email, Password) and toggle(light/dark mode, - // "ctrl+enter"/"enter" - // to send a message directly) - /** - * Open the Settings screen. - * Only suited for Dev/Error mode. - * Avoid usage. - * - * @since Envoy v0.1-alpha - */ - public static void open() { open(new SettingsScreen()); } - - /** - * Opens the Settings screen.
- * Use preferably since everyone is already initialised.
- * It personalises the screen more. - * - * @param username The name of the User - * @param Email The Email that is associated with that Account - * @since Envoy v0.1-alpha - */ - public static void open(String username) {// , String Email) {AUSKLAMMERN, WENN ANMELDUNG PER - // EMAIL IMPLEMENTIERT IST! - open(new SettingsScreen(username)); - } - - public static void open(SettingsScreen dialog) { - dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - dialog.setModal(true); - dialog.setVisible(true); - } - - /** - * Builds the Settings screen.
- * Use only as Dev/Error Mode.
- * Avoid usage. - * - * @since Envoy v0.1-alpha - */ - public SettingsScreen() { - setBackground(Color.BLACK); - setBounds(100, 100, 450, 300); - getContentPane().setLayout(new BorderLayout()); - contentPanel.setBackground(Color.BLACK); - contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); - getContentPane().add(contentPanel, BorderLayout.CENTER); - contentPanel.setLayout(new BorderLayout(0, 0)); - { - JPanel buttonPane = new JPanel(); - buttonPane.setBackground(Color.BLACK); - getContentPane().add(buttonPane, BorderLayout.SOUTH); - buttonPane.setLayout(new BorderLayout(0, 0)); - { - JButton okButton = new JButton("Save"); - okButton.setActionCommand("OK"); - buttonPane.add(okButton, BorderLayout.EAST); - getRootPane().setDefaultButton(okButton); - okButton.addActionListener((evt) -> { - // Hier später die Daten abspeichern, wenn Datenmodell implementiert ist - dispose(); - }); - } - { - JButton cancelButton = new JButton("Cancel"); - cancelButton.setActionCommand("Cancel"); - buttonPane.add(cancelButton, BorderLayout.WEST); - - cancelButton.addActionListener((evt) -> { dispose(); }); - } - } - } - - /** - * Builds the Settings screen.
- * Use preferreably since everyone is already initialised.
- * It personalises the screen more. - * - * @param Username The name of the User - * @param Email The Email that is associated with that Account - * @since Envoy v0.1-alpha - */ - public SettingsScreen(String Username) {// , String Email, String hashedPwd) {AUSKLAMMERN, WENN ANMELDUNG PER EMAIL - // IMPLEMENTIERT IST! - setBackground(Color.BLACK); - setBounds(100, 100, 450, 300); - getContentPane().setLayout(new BorderLayout()); - contentPanel.setBackground(Color.BLACK); - contentPanel.setLayout(new FlowLayout()); - contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); - getContentPane().add(contentPanel, BorderLayout.CENTER); - { - JPanel buttonPane = new JPanel(); - buttonPane.setBackground(Color.BLACK); - getContentPane().add(buttonPane, BorderLayout.SOUTH); - buttonPane.setLayout(new BorderLayout(0, 0)); - { - JButton okButton = new JButton("Save"); - okButton.setActionCommand("OK"); - buttonPane.add(okButton, BorderLayout.EAST); - getRootPane().setDefaultButton(okButton); - okButton.addActionListener((evt) -> { - // Hier später die Daten abspeichern, wenn Datenmodell implementiert ist - dispose(); - }); - } - { - JButton cancelButton = new JButton("Cancel"); - cancelButton.setActionCommand("Cancel"); - buttonPane.add(cancelButton, BorderLayout.WEST); - - cancelButton.addActionListener((evt) -> { dispose(); }); - } - } - } - - /** - * @return true if Enter should be used to send a message instead of ctrl+enter - * @since Envoy v0.1-alpha - */ - public static boolean isEnterToSend() { return enterToSend; } - - /** - * @param enterToSend
- * toggles whether a message should be sent via - *
- * buttonpress "enter" or "ctrl"+"enter" - * @since Envoy v0.1-alpha - */ - public static void setEnterToSend(boolean enterForSend) { enterToSend = enterForSend; } - // TODO: Should be changed to private, but later to avoid warnings -} From 0f4e3d849a8e6624e06336d12eeba6cd9a362fa8 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 21 Dec 2019 22:36:59 +0100 Subject: [PATCH 150/474] Update README.md to an appropriate level --- README.md | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f684ac7..c52e7fd 100644 --- a/README.md +++ b/README.md @@ -1 +1,40 @@ -# envoy-client \ No newline at end of file +# Envoy Client + + + +**Envoy Client** is one of two repositories needed to use the messenger Envoy.
+The other one is **Envoy Common**.
+In the future, Envoy Common might be discarded, but for now, both Repositories are required in order to use Envoy to send messages to other people.
+

+ +## Features + +Envoy Client features a lot of things and many more are yet to come. +Currently existing features are: + +* Users + * Saving and loading of messages + * Login via name + * Settings to change the behavior of _Envoy_ +* UI + * Appealing user interface + * Changeable themes that store the colors used in _Envoy_ + * Possibility to run _Envoy_ in the Background once it has been started + * **Attention**: currently works solely on Windows and Mac + * Possibility to exit _Envoy_ +* Connectivity + * Sending messages to another person via a predefined server + * Offline mode +* Programming + * API to change default configuration + * Advanced logging possibilities + * Access without Admin rights possible via local message storage in the home folder + * Tons of Events to interact with + * Detailed Javadoc to improve readability of code + +## Resources + +* [API Reference (later on)](https://github.com/informatik-ag-ngl/envoy-client/wiki) +* [Release Notes](https://github.com/informatik-ag-ngl/envoy-client/releases) +* [Gallery (later on)](https://github.com/informatik-ag-ngl/envoy-client/wiki/Gallery) +* [Wiki](https://github.com/informatik-ag-ngl/envoy-client/wiki) From 7a3edb932df55a1d14d06523fe97caa80603df14 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sun, 22 Dec 2019 18:07:30 +0100 Subject: [PATCH 151/474] PrimaryToggleSwitch * Adds a component, that can be used to toggle between two options. * Is built to be able to be used for any event, that is structured like the OnCloseChangeEvent class. --- .../client/event/OnCloseChangeEvent.java | 25 ++++ .../envoy/client/ui/PrimaryToggleSwitch.java | 118 ++++++++++++++++++ .../envoy/client/ui/settings/General.java | 70 +++++++++++ .../client/ui/settings/SettingsScreen.java | 1 + 4 files changed, 214 insertions(+) create mode 100644 src/main/java/envoy/client/event/OnCloseChangeEvent.java create mode 100644 src/main/java/envoy/client/ui/PrimaryToggleSwitch.java create mode 100644 src/main/java/envoy/client/ui/settings/General.java diff --git a/src/main/java/envoy/client/event/OnCloseChangeEvent.java b/src/main/java/envoy/client/event/OnCloseChangeEvent.java new file mode 100644 index 0000000..cefc375 --- /dev/null +++ b/src/main/java/envoy/client/event/OnCloseChangeEvent.java @@ -0,0 +1,25 @@ +package envoy.client.event; + +/** + * Project: envoy-client
+ * File: OnCloseChangeEvent.java
+ * Created: 22 Dec 2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.3-alpha + */ +public class OnCloseChangeEvent implements Event{ + + private Integer closeMode; + + /** + * @param closeMode This is the on close mode for the client, that should be set. + *
0 = ExitOnClose
1 = HideOnClose + * @since Envoy 0.3-alpha + */ + public OnCloseChangeEvent(int closeMode) {this.closeMode = closeMode;} + + @Override + public Integer get() { return closeMode; } + +} diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java new file mode 100644 index 0000000..aa36cca --- /dev/null +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -0,0 +1,118 @@ +package envoy.client.ui; +import java.awt.*; +import java.lang.reflect.Constructor; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.*; + +import envoy.client.Settings; +import envoy.client.event.Event; +import envoy.client.event.EventBus; +import envoy.client.event.EventHandler; +import envoy.client.event.OnCloseChangeEvent; +import envoy.client.ui.settings.ThemeCustomizationPanel; +import envoy.client.util.EnvoyLog; + +/** + * This Component can be used to toggle between two options. e.g. on and off

+ * + * Project: envoy-client
+ * File: PrimaryToggleSwitch.java
+ * Created: 21 Dec 2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.2-alpha + */ +public class PrimaryToggleSwitch extends JPanel{ + + private static final long serialVersionUID = -721155303106833184L; + private boolean initialState; + JButton b = new JButton(""); + private boolean currentState; + private int variable; + private static final Logger logger = EnvoyLog.getLogger(PrimaryToggleSwitch.class.getSimpleName()); + + /** + * @param initialState The state the toggleSwitch is standardly set to.
true: off
false: on + * @param eventName the path of the event class + * @since Envoy v0.3-alpha + */ + @SuppressWarnings({ "rawtypes", "unused" }) + public PrimaryToggleSwitch(boolean initialState, String eventName) { + super(); + setEnabled(true); + setVisible(true); + this.initialState = initialState; + setPreferredSize(new Dimension(50, 25)); + b.setPreferredSize(new Dimension(25, 25)); + b.setBackground(Settings.getInstance().getThemes() + .get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); + + GridBagLayout gbl_toggleSwitch = new GridBagLayout(); + gbl_toggleSwitch.columnWidths = new int[] { 1, 1 }; + gbl_toggleSwitch.rowHeights = new int[] { 1}; + gbl_toggleSwitch.columnWeights = new double[] { 1.0, 1.0 }; + gbl_toggleSwitch.rowWeights = new double[] {1.0 }; + + setLayout(gbl_toggleSwitch); + + setState(initialState); + + b.addActionListener((evt) -> { + try { + Class c = Class.forName(eventName); + Class[] types = {int.class}; + Constructor constructor = c.getConstructor(types); + + Object[] parameters = {variable}; + Object instanceOfC = constructor.newInstance(parameters); + + EventBus.getInstance().dispatch((Event) constructor.newInstance(parameters)); + setState(!currentState); + this.revalidate(); + this.repaint(); + } catch (Exception e) { + logger.info("An error occured while changing the setting: " + e); + e.printStackTrace(); + } + }); + + repaint(); + } + + public void paintComponent(Graphics g) { + g.setColor(Color.LIGHT_GRAY); + g.fillRect(0, 0, 50, 25); + g.setColor(Color.GREEN); + g.fillRect(0, 0, 25, 25); + } + + /** + * This method sets the state of the {@link PrimaryToggleSwitch}. + * + * @param state This is the state of the {@link PrimaryToggleSwitch}, that should be set.
true: off
false: on + * @since Envoy 0.3-alpha + */ + public void setState (boolean state){ + if(state) { + GridBagConstraints gbc_toggleButton = new GridBagConstraints(); + gbc_toggleButton.anchor = GridBagConstraints.WEST; + gbc_toggleButton.gridx = 0; + gbc_toggleButton.gridy = 0; + + add(b, gbc_toggleButton); + currentState = true; + variable = 1; + }else { + GridBagConstraints gbc_toggleButton = new GridBagConstraints(); + gbc_toggleButton.anchor = GridBagConstraints.EAST; + gbc_toggleButton.gridx = 1; + gbc_toggleButton.gridy = 0; + + add(b, gbc_toggleButton); + currentState = false; + variable = 0; + } + } +} diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java new file mode 100644 index 0000000..f112f7f --- /dev/null +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -0,0 +1,70 @@ +package envoy.client.ui.settings; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionListener; + +import envoy.client.event.EventBus; +import envoy.client.event.OnCloseChangeEvent; +import envoy.client.event.ThemeChangeEvent; +import envoy.client.ui.PrimaryToggleSwitch; + +/** + * Displays GUI components that allow general settings regarding the client.
+ *
+ * + * Project: envoy-client
+ * File: General.java
+ * Created: 21 Dec 2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.2-alpha + */ +public class General extends SettingsPanel { + + private static final long serialVersionUID = -7470848775130754239L; + + private String variable = "exit"; + PrimaryToggleSwitch toggleSwitch = new PrimaryToggleSwitch(false,"envoy.client.event.OnCloseChangeEvent"); + + /** + * This is the constructor for the General class. Here the user can set general settings for the client. + * @since Envoy 0.3-alpha + */ + public General() { + + GridBagLayout gbl_general = new GridBagLayout(); + gbl_general.columnWidths = new int[] { 1, 1 }; + gbl_general.rowHeights = new int[] { 1, 1 }; + gbl_general.columnWeights = new double[] { 1.0, 1.0 }; + gbl_general.rowWeights = new double[] { 1.0, 1.0 }; + + setLayout(gbl_general); + + GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); + gbc_toggleSwitch.gridx = 0; + gbc_toggleSwitch.gridy = 0; + + add(toggleSwitch, gbc_toggleSwitch); + + EventBus.getInstance().register(OnCloseChangeEvent.class, (evt) -> changeOnClose(((OnCloseChangeEvent) evt).get())); + } + + /** + * This method changes the on close mode of the client. + * + * @param state This is the integer that defines weather the toggleSwitch is on or off. + * @since Envoy v0.3-alpha + */ + public void changeOnClose(int state) { + System.out.println(state); + } + + @Override + public ActionListener getOkButtonAction() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 29bbe92..d0e4b8f 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -57,6 +57,7 @@ public class SettingsScreen extends JDialog { public SettingsScreen() { // Initialize settings pages Map> panels = new HashMap<>(); + panels.put("General", General.class); panels.put("Color Themes", ThemeCustomizationPanel.class); setBounds(10, 10, 450, 650); From b577f785b5711ce844352423b530c01ea01f7dbc Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sun, 22 Dec 2019 21:28:13 +0100 Subject: [PATCH 152/474] OnCloseMode * Toggle Switch in general settings effects the onCloseMode of the window. * Saving in prefs. * Styled the general settings screen and added some text. --- src/main/java/envoy/client/Settings.java | 19 +++- .../envoy/client/ui/PrimaryToggleSwitch.java | 11 ++- src/main/java/envoy/client/ui/Startup.java | 7 +- .../envoy/client/ui/settings/General.java | 91 +++++++++++++++++-- 4 files changed, 115 insertions(+), 13 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index b1c0b6b..e0c40b1 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -28,6 +28,7 @@ public class Settings { private boolean enterToSend = true; private Map themes; private String currentTheme; + private int currentOnCloseMode; /** * Required to save the settings. @@ -64,7 +65,8 @@ public class Settings { private void load() { setEnterToSend(prefs.getBoolean("enterToSend", true)); setCurrentTheme(prefs.get("theme", "dark")); - + setCurrentOnCloseMode(prefs.getInt("onCloseMode", 1)); + // Load themes from theme file try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) { Object obj = in.readObject(); @@ -94,6 +96,7 @@ public class Settings { public void save() throws IOException { prefs.put("theme", currentTheme); prefs.putBoolean("enterToSend", isEnterToSend()); + prefs.putInt("onCloseMode", currentOnCloseMode); // Save themes to theme file themeFile.createNewFile(); @@ -155,4 +158,18 @@ public class Settings { * @since Envoy v0.2-alpha */ public void setThemes(Map themes) { this.themes = themes; } + + /** + * @return the current on close mode. + * @since Envoy v0.3-alpha + */ + public int getCurrentOnCloseMode () {return currentOnCloseMode;} + + /** + * Sets the current on close mode. + * + * @param currentOnCloseMode the on close mode that should be set. + * @since Envoy v0.3-alpha + */ + public void setCurrentOnCloseMode(int currentOnCloseMode) {this.currentOnCloseMode = currentOnCloseMode;} } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index aa36cca..55b3ebf 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -22,7 +22,7 @@ import envoy.client.util.EnvoyLog; * Created: 21 Dec 2019
* * @author Maximilian Käfer - * @since Envoy v0.2-alpha + * @since Envoy v0.3-alpha */ public class PrimaryToggleSwitch extends JPanel{ @@ -34,6 +34,8 @@ public class PrimaryToggleSwitch extends JPanel{ private static final Logger logger = EnvoyLog.getLogger(PrimaryToggleSwitch.class.getSimpleName()); /** + * This is the constructor for the PrimaryToggleSwitch. + * * @param initialState The state the toggleSwitch is standardly set to.
true: off
false: on * @param eventName the path of the event class * @since Envoy v0.3-alpha @@ -44,8 +46,15 @@ public class PrimaryToggleSwitch extends JPanel{ setEnabled(true); setVisible(true); this.initialState = initialState; + setPreferredSize(new Dimension(50, 25)); + setMinimumSize(new Dimension(50, 25)); + setMaximumSize(new Dimension(50, 25)); + b.setPreferredSize(new Dimension(25, 25)); + b.setMinimumSize(new Dimension(25, 25)); + b.setMaximumSize(new Dimension(25, 25)); + b.setBackground(Settings.getInstance().getThemes() .get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index db9644a..1b33093 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -132,7 +132,12 @@ public class Startup { new StatusTrayIcon(chatWindow).show(); // If the tray icon is supported, hide the chat window on close - chatWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + if(Settings.getInstance().getCurrentOnCloseMode() == 1) { + chatWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + }else { + chatWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + } catch (EnvoyException e) { logger.warning("The StatusTrayIcon is not supported on this platform!"); } diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java index f112f7f..9d49f06 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -4,11 +4,20 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionListener; +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; +import javax.swing.JTextPane; + +import envoy.client.Settings; import envoy.client.event.EventBus; import envoy.client.event.OnCloseChangeEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.PrimaryToggleSwitch; +import envoy.client.ui.Theme; +import envoy.client.util.EnvoyLog; /** * Displays GUI components that allow general settings regarding the client.
@@ -19,35 +28,79 @@ import envoy.client.ui.PrimaryToggleSwitch; * Created: 21 Dec 2019
* * @author Maximilian Käfer - * @since Envoy v0.2-alpha + * @since Envoy v0.3-alpha */ public class General extends SettingsPanel { private static final long serialVersionUID = -7470848775130754239L; + private static final Logger logger = EnvoyLog.getLogger(General.class.getSimpleName()); - private String variable = "exit"; - PrimaryToggleSwitch toggleSwitch = new PrimaryToggleSwitch(false,"envoy.client.event.OnCloseChangeEvent"); + private int state; + + PrimaryToggleSwitch toggleSwitch; + JTextPane onCloseModeText = new JTextPane(); + JTextPane onCloseModeState = new JTextPane(); /** * This is the constructor for the General class. Here the user can set general settings for the client. * @since Envoy 0.3-alpha */ public General() { + Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + + state = Settings.getInstance().getCurrentOnCloseMode(); + if(state == 1) { + toggleSwitch = new PrimaryToggleSwitch(false,"envoy.client.event.OnCloseChangeEvent"); + }else { + toggleSwitch = new PrimaryToggleSwitch(true,"envoy.client.event.OnCloseChangeEvent"); + } + + setBackground(theme.getCellColor()); GridBagLayout gbl_general = new GridBagLayout(); - gbl_general.columnWidths = new int[] { 1, 1 }; - gbl_general.rowHeights = new int[] { 1, 1 }; - gbl_general.columnWeights = new double[] { 1.0, 1.0 }; - gbl_general.rowWeights = new double[] { 1.0, 1.0 }; + gbl_general.columnWidths = new int[] { 1, 1}; + gbl_general.rowHeights = new int[] { 1, 1, 1 }; + gbl_general.columnWeights = new double[] { 1.0, 0.1}; + gbl_general.rowWeights = new double[] { 0.02, 0.0005, 1.0 }; setLayout(gbl_general); GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); - gbc_toggleSwitch.gridx = 0; + gbc_toggleSwitch.gridx = 1; gbc_toggleSwitch.gridy = 0; add(toggleSwitch, gbc_toggleSwitch); + if(state == 0) { + onCloseModeState.setText("OFF"); + }else { + onCloseModeState.setText("ON"); + } + + onCloseModeState.setBackground(theme.getCellColor()); + onCloseModeState.setForeground(theme.getUserNameColor()); + + GridBagConstraints gbc_onCloseModeState = new GridBagConstraints(); + gbc_onCloseModeState.anchor = GridBagConstraints.NORTH; + gbc_onCloseModeState.gridx = 1; + gbc_onCloseModeState.gridy = 1; + + add(onCloseModeState, gbc_onCloseModeState); + + onCloseModeText.setText("Client runs in the background, when window is closed"); + onCloseModeText.setBackground(theme.getBackgroundColor()); + //TODO: Change to inverted color. + onCloseModeText.setForeground(theme.getUserNameColor()); + + GridBagConstraints gbc_onCloseModeText = new GridBagConstraints(); + gbc_onCloseModeText.fill = GridBagConstraints.BOTH; + gbc_onCloseModeText.gridx = 0; + gbc_onCloseModeText.gridy = 0; + gbc_onCloseModeText.gridheight = 2; + gbc_onCloseModeText.insets = new Insets(5, 5, 5, 5); + + add(onCloseModeText, gbc_onCloseModeText); + EventBus.getInstance().register(OnCloseChangeEvent.class, (evt) -> changeOnClose(((OnCloseChangeEvent) evt).get())); } @@ -59,12 +112,30 @@ public class General extends SettingsPanel { */ public void changeOnClose(int state) { System.out.println(state); + this.state = state; + + if(state == 0) { + onCloseModeState.setText("OFF"); + }else { + onCloseModeState.setText("ON"); + } + this.revalidate(); + this.repaint(); } @Override public ActionListener getOkButtonAction() { - // TODO Auto-generated method stub - return null; + return (evt) -> { + if (state != Settings.getInstance().getCurrentOnCloseMode()) { + try { + Settings.getInstance().setCurrentOnCloseMode(state); + JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); + } catch (Exception e) { + logger.info("Close mode could not be changed! " + e); + e.printStackTrace(); + } + } + }; } } From 56afbc542238effe8776554de7ab9c8d6d4332b4 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sun, 22 Dec 2019 21:48:19 +0100 Subject: [PATCH 153/474] Formatting --- src/main/java/envoy/client/Settings.java | 12 +- .../client/event/OnCloseChangeEvent.java | 11 +- .../envoy/client/ui/PrimaryToggleSwitch.java | 115 +++++++++--------- src/main/java/envoy/client/ui/Startup.java | 6 +- .../envoy/client/ui/settings/General.java | 102 ++++++++-------- .../ui/settings/ThemeCustomizationPanel.java | 92 +++++++------- 6 files changed, 168 insertions(+), 170 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index e0c40b1..42bd0f1 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -28,7 +28,7 @@ public class Settings { private boolean enterToSend = true; private Map themes; private String currentTheme; - private int currentOnCloseMode; + private int currentOnCloseMode; /** * Required to save the settings. @@ -66,7 +66,7 @@ public class Settings { setEnterToSend(prefs.getBoolean("enterToSend", true)); setCurrentTheme(prefs.get("theme", "dark")); setCurrentOnCloseMode(prefs.getInt("onCloseMode", 1)); - + // Load themes from theme file try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) { Object obj = in.readObject(); @@ -158,18 +158,18 @@ public class Settings { * @since Envoy v0.2-alpha */ public void setThemes(Map themes) { this.themes = themes; } - + /** * @return the current on close mode. * @since Envoy v0.3-alpha */ - public int getCurrentOnCloseMode () {return currentOnCloseMode;} - + public int getCurrentOnCloseMode() { return currentOnCloseMode; } + /** * Sets the current on close mode. * * @param currentOnCloseMode the on close mode that should be set. * @since Envoy v0.3-alpha */ - public void setCurrentOnCloseMode(int currentOnCloseMode) {this.currentOnCloseMode = currentOnCloseMode;} + public void setCurrentOnCloseMode(int currentOnCloseMode) { this.currentOnCloseMode = currentOnCloseMode; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/event/OnCloseChangeEvent.java b/src/main/java/envoy/client/event/OnCloseChangeEvent.java index cefc375..5cffd37 100644 --- a/src/main/java/envoy/client/event/OnCloseChangeEvent.java +++ b/src/main/java/envoy/client/event/OnCloseChangeEvent.java @@ -8,16 +8,19 @@ package envoy.client.event; * @author Maximilian Käfer * @since Envoy v0.3-alpha */ -public class OnCloseChangeEvent implements Event{ +public class OnCloseChangeEvent implements Event { private Integer closeMode; /** - * @param closeMode This is the on close mode for the client, that should be set. - *
0 = ExitOnClose
1 = HideOnClose + * @param closeMode This is the on close mode for the client, that should be + * set. + *
+ * 0 = ExitOnClose
+ * 1 = HideOnClose * @since Envoy 0.3-alpha */ - public OnCloseChangeEvent(int closeMode) {this.closeMode = closeMode;} + public OnCloseChangeEvent(int closeMode) { this.closeMode = closeMode; } @Override public Integer get() { return closeMode; } diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 55b3ebf..e2469cc 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -1,7 +1,7 @@ package envoy.client.ui; + import java.awt.*; import java.lang.reflect.Constructor; -import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.*; @@ -9,13 +9,12 @@ import javax.swing.*; import envoy.client.Settings; import envoy.client.event.Event; import envoy.client.event.EventBus; -import envoy.client.event.EventHandler; -import envoy.client.event.OnCloseChangeEvent; -import envoy.client.ui.settings.ThemeCustomizationPanel; import envoy.client.util.EnvoyLog; /** - * This Component can be used to toggle between two options. e.g. on and off

+ * This Component can be used to toggle between two options. e.g. on and off + *
+ *
* * Project: envoy-client
* File: PrimaryToggleSwitch.java
@@ -24,20 +23,21 @@ import envoy.client.util.EnvoyLog; * @author Maximilian Käfer * @since Envoy v0.3-alpha */ -public class PrimaryToggleSwitch extends JPanel{ - - private static final long serialVersionUID = -721155303106833184L; - private boolean initialState; - JButton b = new JButton(""); - private boolean currentState; - private int variable; - private static final Logger logger = EnvoyLog.getLogger(PrimaryToggleSwitch.class.getSimpleName()); - +public class PrimaryToggleSwitch extends JPanel { + + private static final long serialVersionUID = -721155303106833184L; + JButton b = new JButton(""); + private boolean currentState; + private int variable; + private static final Logger logger = EnvoyLog.getLogger(PrimaryToggleSwitch.class.getSimpleName()); + /** * This is the constructor for the PrimaryToggleSwitch. * - * @param initialState The state the toggleSwitch is standardly set to.
true: off
false: on - * @param eventName the path of the event class + * @param initialState The state the toggleSwitch is standardly set to.
+ * true: off
+ * false: on + * @param eventName the path of the event class * @since Envoy v0.3-alpha */ @SuppressWarnings({ "rawtypes", "unused" }) @@ -45,38 +45,36 @@ public class PrimaryToggleSwitch extends JPanel{ super(); setEnabled(true); setVisible(true); - this.initialState = initialState; - + setPreferredSize(new Dimension(50, 25)); setMinimumSize(new Dimension(50, 25)); setMaximumSize(new Dimension(50, 25)); - + b.setPreferredSize(new Dimension(25, 25)); b.setMinimumSize(new Dimension(25, 25)); b.setMaximumSize(new Dimension(25, 25)); - - b.setBackground(Settings.getInstance().getThemes() - .get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); - + + b.setBackground(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); + GridBagLayout gbl_toggleSwitch = new GridBagLayout(); - gbl_toggleSwitch.columnWidths = new int[] { 1, 1 }; - gbl_toggleSwitch.rowHeights = new int[] { 1}; - gbl_toggleSwitch.columnWeights = new double[] { 1.0, 1.0 }; - gbl_toggleSwitch.rowWeights = new double[] {1.0 }; + gbl_toggleSwitch.columnWidths = new int[] { 1, 1 }; + gbl_toggleSwitch.rowHeights = new int[] { 1 }; + gbl_toggleSwitch.columnWeights = new double[] { 1.0, 1.0 }; + gbl_toggleSwitch.rowWeights = new double[] { 1.0 }; setLayout(gbl_toggleSwitch); - + setState(initialState); - + b.addActionListener((evt) -> { try { - Class c = Class.forName(eventName); - Class[] types = {int.class}; - Constructor constructor = c.getConstructor(types); - - Object[] parameters = {variable}; - Object instanceOfC = constructor.newInstance(parameters); - + Class c = Class.forName(eventName); + Class[] types = { int.class }; + Constructor constructor = c.getConstructor(types); + + Object[] parameters = { variable }; + Object instanceOfC = constructor.newInstance(parameters); + EventBus.getInstance().dispatch((Event) constructor.newInstance(parameters)); setState(!currentState); this.revalidate(); @@ -86,42 +84,45 @@ public class PrimaryToggleSwitch extends JPanel{ e.printStackTrace(); } }); - + repaint(); } - + public void paintComponent(Graphics g) { g.setColor(Color.LIGHT_GRAY); g.fillRect(0, 0, 50, 25); g.setColor(Color.GREEN); g.fillRect(0, 0, 25, 25); } - + /** * This method sets the state of the {@link PrimaryToggleSwitch}. * - * @param state This is the state of the {@link PrimaryToggleSwitch}, that should be set.
true: off
false: on + * @param state This is the state of the {@link PrimaryToggleSwitch}, that + * should be set.
+ * true: off
+ * false: on * @since Envoy 0.3-alpha */ - public void setState (boolean state){ - if(state) { + public void setState(boolean state) { + if (state) { GridBagConstraints gbc_toggleButton = new GridBagConstraints(); - gbc_toggleButton.anchor = GridBagConstraints.WEST; - gbc_toggleButton.gridx = 0; - gbc_toggleButton.gridy = 0; - - add(b, gbc_toggleButton); - currentState = true; - variable = 1; - }else { - GridBagConstraints gbc_toggleButton = new GridBagConstraints(); - gbc_toggleButton.anchor = GridBagConstraints.EAST; - gbc_toggleButton.gridx = 1; - gbc_toggleButton.gridy = 0; - + gbc_toggleButton.anchor = GridBagConstraints.WEST; + gbc_toggleButton.gridx = 0; + gbc_toggleButton.gridy = 0; + add(b, gbc_toggleButton); - currentState = false; - variable = 0; + currentState = true; + variable = 1; + } else { + GridBagConstraints gbc_toggleButton = new GridBagConstraints(); + gbc_toggleButton.anchor = GridBagConstraints.EAST; + gbc_toggleButton.gridx = 1; + gbc_toggleButton.gridy = 0; + + add(b, gbc_toggleButton); + currentState = false; + variable = 0; } } } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 1b33093..547be9a 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -132,12 +132,12 @@ public class Startup { new StatusTrayIcon(chatWindow).show(); // If the tray icon is supported, hide the chat window on close - if(Settings.getInstance().getCurrentOnCloseMode() == 1) { + if (Settings.getInstance().getCurrentOnCloseMode() == 1) { chatWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - }else { + } else { chatWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } - + } catch (EnvoyException e) { logger.warning("The StatusTrayIcon is not supported on this platform!"); } diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java index 9d49f06..017bb85 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -4,8 +4,6 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionListener; -import java.util.Arrays; -import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; @@ -14,7 +12,6 @@ import javax.swing.JTextPane; import envoy.client.Settings; import envoy.client.event.EventBus; import envoy.client.event.OnCloseChangeEvent; -import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.PrimaryToggleSwitch; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; @@ -31,98 +28,101 @@ import envoy.client.util.EnvoyLog; * @since Envoy v0.3-alpha */ public class General extends SettingsPanel { - - private static final long serialVersionUID = -7470848775130754239L; - private static final Logger logger = EnvoyLog.getLogger(General.class.getSimpleName()); - + + private static final long serialVersionUID = -7470848775130754239L; + private static final Logger logger = EnvoyLog.getLogger(General.class.getSimpleName()); + private int state; - - PrimaryToggleSwitch toggleSwitch; - JTextPane onCloseModeText = new JTextPane(); - JTextPane onCloseModeState = new JTextPane(); - + + PrimaryToggleSwitch toggleSwitch; + JTextPane onCloseModeText = new JTextPane(); + JTextPane onCloseModeState = new JTextPane(); + /** - * This is the constructor for the General class. Here the user can set general settings for the client. + * This is the constructor for the General class. Here the user can set general + * settings for the client. + * * @since Envoy 0.3-alpha */ public General() { Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - + state = Settings.getInstance().getCurrentOnCloseMode(); - if(state == 1) { - toggleSwitch = new PrimaryToggleSwitch(false,"envoy.client.event.OnCloseChangeEvent"); - }else { - toggleSwitch = new PrimaryToggleSwitch(true,"envoy.client.event.OnCloseChangeEvent"); + if (state == 1) { + toggleSwitch = new PrimaryToggleSwitch(false, "envoy.client.event.OnCloseChangeEvent"); + } else { + toggleSwitch = new PrimaryToggleSwitch(true, "envoy.client.event.OnCloseChangeEvent"); } - + setBackground(theme.getCellColor()); - + GridBagLayout gbl_general = new GridBagLayout(); - gbl_general.columnWidths = new int[] { 1, 1}; - gbl_general.rowHeights = new int[] { 1, 1, 1 }; - gbl_general.columnWeights = new double[] { 1.0, 0.1}; - gbl_general.rowWeights = new double[] { 0.02, 0.0005, 1.0 }; + gbl_general.columnWidths = new int[] { 1, 1 }; + gbl_general.rowHeights = new int[] { 1, 1, 1 }; + gbl_general.columnWeights = new double[] { 1.0, 0.1 }; + gbl_general.rowWeights = new double[] { 0.02, 0.0005, 1.0 }; setLayout(gbl_general); - + GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); - gbc_toggleSwitch.gridx = 1; - gbc_toggleSwitch.gridy = 0; + gbc_toggleSwitch.gridx = 1; + gbc_toggleSwitch.gridy = 0; add(toggleSwitch, gbc_toggleSwitch); - - if(state == 0) { + + if (state == 0) { onCloseModeState.setText("OFF"); - }else { + } else { onCloseModeState.setText("ON"); } - + onCloseModeState.setBackground(theme.getCellColor()); onCloseModeState.setForeground(theme.getUserNameColor()); - + GridBagConstraints gbc_onCloseModeState = new GridBagConstraints(); - gbc_onCloseModeState.anchor = GridBagConstraints.NORTH; - gbc_onCloseModeState.gridx = 1; - gbc_onCloseModeState.gridy = 1; + gbc_onCloseModeState.anchor = GridBagConstraints.NORTH; + gbc_onCloseModeState.gridx = 1; + gbc_onCloseModeState.gridy = 1; add(onCloseModeState, gbc_onCloseModeState); - + onCloseModeText.setText("Client runs in the background, when window is closed"); onCloseModeText.setBackground(theme.getBackgroundColor()); - //TODO: Change to inverted color. + // TODO: Change to inverted color. onCloseModeText.setForeground(theme.getUserNameColor()); - + GridBagConstraints gbc_onCloseModeText = new GridBagConstraints(); - gbc_onCloseModeText.fill = GridBagConstraints.BOTH; - gbc_onCloseModeText.gridx = 0; - gbc_onCloseModeText.gridy = 0; - gbc_onCloseModeText.gridheight = 2; - gbc_onCloseModeText.insets = new Insets(5, 5, 5, 5); + gbc_onCloseModeText.fill = GridBagConstraints.BOTH; + gbc_onCloseModeText.gridx = 0; + gbc_onCloseModeText.gridy = 0; + gbc_onCloseModeText.gridheight = 2; + gbc_onCloseModeText.insets = new Insets(5, 5, 5, 5); add(onCloseModeText, gbc_onCloseModeText); - + EventBus.getInstance().register(OnCloseChangeEvent.class, (evt) -> changeOnClose(((OnCloseChangeEvent) evt).get())); } - + /** * This method changes the on close mode of the client. * - * @param state This is the integer that defines weather the toggleSwitch is on or off. + * @param state This is the integer that defines weather the toggleSwitch is on + * or off. * @since Envoy v0.3-alpha */ public void changeOnClose(int state) { System.out.println(state); this.state = state; - - if(state == 0) { + + if (state == 0) { onCloseModeState.setText("OFF"); - }else { + } else { onCloseModeState.setText("ON"); } this.revalidate(); this.repaint(); } - + @Override public ActionListener getOkButtonAction() { return (evt) -> { @@ -130,7 +130,7 @@ public class General extends SettingsPanel { try { Settings.getInstance().setCurrentOnCloseMode(state); JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); - } catch (Exception e) { + } catch (Exception e) { logger.info("Close mode could not be changed! " + e); e.printStackTrace(); } diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 45663af..959690e 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -34,10 +34,10 @@ public class ThemeCustomizationPanel extends SettingsPanel { private JPanel colorsPanel = new JPanel(); - private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]); - private JComboBox themes = new JComboBox<>(themeArray); - private Theme temporaryTheme, selectedTheme; - private boolean themeChanged = false; + private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]); + private JComboBox themes = new JComboBox<>(themeArray); + private Theme temporaryTheme, selectedTheme; + private boolean themeChanged = false; private final Insets insets = new Insets(5, 5, 5, 5); @@ -51,15 +51,14 @@ public class ThemeCustomizationPanel extends SettingsPanel { * @since Envoy v0.2-alpha */ public ThemeCustomizationPanel() { - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); GridBagLayout gbl_themeLayout = new GridBagLayout(); - gbl_themeLayout.columnWidths = new int[] { 1, 1 }; - gbl_themeLayout.rowHeights = new int[] { 1, 1 }; - gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 }; - gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0 }; + gbl_themeLayout.columnWidths = new int[] { 1, 1 }; + gbl_themeLayout.rowHeights = new int[] { 1, 1 }; + gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 }; + gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0 }; setLayout(gbl_themeLayout); @@ -76,20 +75,20 @@ public class ThemeCustomizationPanel extends SettingsPanel { }); GridBagConstraints gbc_themes = new GridBagConstraints(); - gbc_themes.fill = GridBagConstraints.HORIZONTAL; - gbc_themes.gridwidth = 2; - gbc_themes.gridx = 0; - gbc_themes.gridy = 0; - gbc_themes.anchor = GridBagConstraints.NORTHWEST; - gbc_themes.insets = new Insets(10, 10, 20, 10); + gbc_themes.fill = GridBagConstraints.HORIZONTAL; + gbc_themes.gridwidth = 2; + gbc_themes.gridx = 0; + gbc_themes.gridy = 0; + gbc_themes.anchor = GridBagConstraints.NORTHWEST; + gbc_themes.insets = new Insets(10, 10, 20, 10); add(themes, gbc_themes); GridBagLayout gbl_colorCustomizations = new GridBagLayout(); - gbl_colorCustomizations.columnWidths = new int[] { 1, 1 }; - gbl_colorCustomizations.rowHeights = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - gbl_colorCustomizations.columnWeights = new double[] { 1, 1 }; - gbl_colorCustomizations.rowWeights = new double[] { 1, 1, 1, 1, 1, 1, 1, 1 }; + gbl_colorCustomizations.columnWidths = new int[] { 1, 1 }; + gbl_colorCustomizations.rowHeights = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + gbl_colorCustomizations.columnWeights = new double[] { 1, 1 }; + gbl_colorCustomizations.rowWeights = new double[] { 1, 1, 1, 1, 1, 1, 1, 1 }; colorsPanel.setLayout(gbl_colorCustomizations); @@ -97,12 +96,12 @@ public class ThemeCustomizationPanel extends SettingsPanel { buildCustomizeElements(theme); GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); - gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; - gbc_colorsPanel.gridx = 0; - gbc_colorsPanel.gridy = 1; - gbc_colorsPanel.gridwidth = 2; - gbc_colorsPanel.anchor = GridBagConstraints.NORTHWEST; - gbc_colorsPanel.insets = insets; + gbc_colorsPanel.fill = GridBagConstraints.HORIZONTAL; + gbc_colorsPanel.gridx = 0; + gbc_colorsPanel.gridy = 1; + gbc_colorsPanel.gridwidth = 2; + gbc_colorsPanel.anchor = GridBagConstraints.NORTHWEST; + gbc_colorsPanel.insets = insets; add(colorsPanel, gbc_colorsPanel); colorsPanel.setBackground(theme.getCellColor()); @@ -122,11 +121,10 @@ public class ThemeCustomizationPanel extends SettingsPanel { String name = JOptionPane.showInputDialog("Enter a name for the new theme"); logger.log(Level.FINEST, name); Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); - themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); - themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(name).getThemeName(); + themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); + themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(name).getThemeName(); - temporaryTheme = new Theme("temporaryTheme", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); themes.addItem(themeArray[themeArray.length - 1]); themes.setSelectedIndex(themeArray.length - 1); @@ -172,10 +170,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { private void buildCustomizeElements(Theme theme) { buildCustomizeElement(theme, theme.getBackgroundColor(), "Background", "backgroundColor", 1); buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor", 2); - buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", - "interactableForegroundColor", 3); - buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", - "interactableBackgroundColor", 4); + buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3); + buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor", 4); buildCustomizeElement(theme, theme.getMessageColorChat(), "Messages Chat", "messageColorChat", 5); buildCustomizeElement(theme, theme.getDateColorChat(), "Date Chat", "dateColorCat", 6); buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor", 7); @@ -184,8 +180,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { } private void buildCustomizeElement(Theme theme, Color color, String name, String colorName, int gridy) { - JButton button = new JButton(); - JTextPane textPane = new JTextPane(); + JButton button = new JButton(); + JTextPane textPane = new JTextPane(); textPane.setFont(new Font("Arial", Font.PLAIN, 14)); textPane.setBackground(theme.getBackgroundColor()); @@ -215,25 +211,23 @@ public class ThemeCustomizationPanel extends SettingsPanel { }); GridBagConstraints gbc_textPane = new GridBagConstraints(); - gbc_textPane.fill = GridBagConstraints.BOTH; - gbc_textPane.gridx = 0; - gbc_textPane.gridy = gridy; - gbc_textPane.anchor = GridBagConstraints.CENTER; - gbc_textPane.insets = insets; + gbc_textPane.fill = GridBagConstraints.BOTH; + gbc_textPane.gridx = 0; + gbc_textPane.gridy = gridy; + gbc_textPane.anchor = GridBagConstraints.CENTER; + gbc_textPane.insets = insets; colorsPanel.add(textPane, gbc_textPane); GridBagConstraints gbc_button = new GridBagConstraints(); - gbc_button.fill = GridBagConstraints.BOTH; - gbc_button.gridx = 1; - gbc_button.gridy = gridy; - gbc_button.anchor = GridBagConstraints.CENTER; - gbc_button.insets = insets; + gbc_button.fill = GridBagConstraints.BOTH; + gbc_button.gridx = 1; + gbc_button.gridy = gridy; + gbc_button.anchor = GridBagConstraints.CENTER; + gbc_button.insets = insets; colorsPanel.add(button, gbc_button); } - private Color getInvertedColor(Color color) { - return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); - } + private Color getInvertedColor(Color color) { return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); } } From b0b9f63861f544455b85d5af5ea9dc0324954c7f Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Mon, 23 Dec 2019 00:03:22 +0100 Subject: [PATCH 154/474] Enter to Send and Revising * Revised style and improved object architecture * Added Enter to Send mechanism. --- src/main/java/envoy/client/Settings.java | 10 +- .../envoy/client/event/EnterToSendEvent.java | 27 +++ .../client/event/OnCloseChangeEvent.java | 12 +- .../envoy/client/ui/PrimaryToggleSwitch.java | 8 +- src/main/java/envoy/client/ui/Startup.java | 2 +- .../envoy/client/ui/settings/General.java | 169 ++++++++++++------ 6 files changed, 154 insertions(+), 74 deletions(-) create mode 100644 src/main/java/envoy/client/event/EnterToSendEvent.java diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 42bd0f1..5e15743 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -28,7 +28,7 @@ public class Settings { private boolean enterToSend = true; private Map themes; private String currentTheme; - private int currentOnCloseMode; + private boolean currentOnCloseMode; /** * Required to save the settings. @@ -65,7 +65,7 @@ public class Settings { private void load() { setEnterToSend(prefs.getBoolean("enterToSend", true)); setCurrentTheme(prefs.get("theme", "dark")); - setCurrentOnCloseMode(prefs.getInt("onCloseMode", 1)); + setCurrentOnCloseMode(prefs.getBoolean("onCloseMode", true)); // Load themes from theme file try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) { @@ -96,7 +96,7 @@ public class Settings { public void save() throws IOException { prefs.put("theme", currentTheme); prefs.putBoolean("enterToSend", isEnterToSend()); - prefs.putInt("onCloseMode", currentOnCloseMode); + prefs.putBoolean("onCloseMode", currentOnCloseMode); // Save themes to theme file themeFile.createNewFile(); @@ -163,7 +163,7 @@ public class Settings { * @return the current on close mode. * @since Envoy v0.3-alpha */ - public int getCurrentOnCloseMode() { return currentOnCloseMode; } + public boolean getCurrentOnCloseMode() { return currentOnCloseMode; } /** * Sets the current on close mode. @@ -171,5 +171,5 @@ public class Settings { * @param currentOnCloseMode the on close mode that should be set. * @since Envoy v0.3-alpha */ - public void setCurrentOnCloseMode(int currentOnCloseMode) { this.currentOnCloseMode = currentOnCloseMode; } + public void setCurrentOnCloseMode(boolean currentOnCloseMode) { this.currentOnCloseMode = currentOnCloseMode; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/event/EnterToSendEvent.java b/src/main/java/envoy/client/event/EnterToSendEvent.java new file mode 100644 index 0000000..f96d13e --- /dev/null +++ b/src/main/java/envoy/client/event/EnterToSendEvent.java @@ -0,0 +1,27 @@ +package envoy.client.event; + +/** + * Project: envoy-client
+ * File: EnterToSendEvent.java
+ * Created: 22 Dec 2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.3-alpha + */ +public class EnterToSendEvent implements Event { + + private boolean mode; + + /** + * @param mode This is the enter to sent mode when sending messages. + *
+ * true = Enter to Send Messages
+ * false = Enter to do a line break + * @since Envoy 0.3-alpha + */ + public EnterToSendEvent(boolean mode) { this.mode = mode; } + + @Override + public Boolean get() { return mode; } + +} diff --git a/src/main/java/envoy/client/event/OnCloseChangeEvent.java b/src/main/java/envoy/client/event/OnCloseChangeEvent.java index 5cffd37..717a5da 100644 --- a/src/main/java/envoy/client/event/OnCloseChangeEvent.java +++ b/src/main/java/envoy/client/event/OnCloseChangeEvent.java @@ -8,21 +8,21 @@ package envoy.client.event; * @author Maximilian Käfer * @since Envoy v0.3-alpha */ -public class OnCloseChangeEvent implements Event { +public class OnCloseChangeEvent implements Event { - private Integer closeMode; + private boolean closeMode; /** * @param closeMode This is the on close mode for the client, that should be * set. *
- * 0 = ExitOnClose
- * 1 = HideOnClose + * true = ExitOnClose
+ * false = HideOnClose * @since Envoy 0.3-alpha */ - public OnCloseChangeEvent(int closeMode) { this.closeMode = closeMode; } + public OnCloseChangeEvent(boolean closeMode) { this.closeMode = closeMode; } @Override - public Integer get() { return closeMode; } + public Boolean get() { return closeMode; } } diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index e2469cc..361db5d 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -28,7 +28,7 @@ public class PrimaryToggleSwitch extends JPanel { private static final long serialVersionUID = -721155303106833184L; JButton b = new JButton(""); private boolean currentState; - private int variable; + private boolean variable; private static final Logger logger = EnvoyLog.getLogger(PrimaryToggleSwitch.class.getSimpleName()); /** @@ -69,7 +69,7 @@ public class PrimaryToggleSwitch extends JPanel { b.addActionListener((evt) -> { try { Class c = Class.forName(eventName); - Class[] types = { int.class }; + Class[] types = { boolean.class }; Constructor constructor = c.getConstructor(types); Object[] parameters = { variable }; @@ -113,7 +113,7 @@ public class PrimaryToggleSwitch extends JPanel { add(b, gbc_toggleButton); currentState = true; - variable = 1; + variable = true; } else { GridBagConstraints gbc_toggleButton = new GridBagConstraints(); gbc_toggleButton.anchor = GridBagConstraints.EAST; @@ -122,7 +122,7 @@ public class PrimaryToggleSwitch extends JPanel { add(b, gbc_toggleButton); currentState = false; - variable = 0; + variable = false; } } } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 547be9a..d2f7125 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -132,7 +132,7 @@ public class Startup { new StatusTrayIcon(chatWindow).show(); // If the tray icon is supported, hide the chat window on close - if (Settings.getInstance().getCurrentOnCloseMode() == 1) { + if (Settings.getInstance().getCurrentOnCloseMode() == true) { chatWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); } else { chatWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java index 017bb85..e922359 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -10,6 +10,7 @@ import javax.swing.JOptionPane; import javax.swing.JTextPane; import envoy.client.Settings; +import envoy.client.event.EnterToSendEvent; import envoy.client.event.EventBus; import envoy.client.event.OnCloseChangeEvent; import envoy.client.ui.PrimaryToggleSwitch; @@ -31,12 +32,17 @@ public class General extends SettingsPanel { private static final long serialVersionUID = -7470848775130754239L; private static final Logger logger = EnvoyLog.getLogger(General.class.getSimpleName()); - - private int state; + private Theme theme; + private boolean onCloseState; + private boolean enterToSend; PrimaryToggleSwitch toggleSwitch; - JTextPane onCloseModeText = new JTextPane(); - JTextPane onCloseModeState = new JTextPane(); + JTextPane onCloseModeTextPane = new JTextPane(); + JTextPane onCloseModeStatePane = new JTextPane(); + + PrimaryToggleSwitch toggleSwitchEnterToSend; + JTextPane enterToSendTextPane = new JTextPane(); + JTextPane enterToSendStatePane = new JTextPane(); /** * This is the constructor for the General class. Here the user can set general @@ -45,62 +51,35 @@ public class General extends SettingsPanel { * @since Envoy 0.3-alpha */ public General() { - Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - - state = Settings.getInstance().getCurrentOnCloseMode(); - if (state == 1) { - toggleSwitch = new PrimaryToggleSwitch(false, "envoy.client.event.OnCloseChangeEvent"); - } else { - toggleSwitch = new PrimaryToggleSwitch(true, "envoy.client.event.OnCloseChangeEvent"); - } + theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); setBackground(theme.getCellColor()); GridBagLayout gbl_general = new GridBagLayout(); gbl_general.columnWidths = new int[] { 1, 1 }; - gbl_general.rowHeights = new int[] { 1, 1, 1 }; + gbl_general.rowHeights = new int[] { 1, 1, 1, 1, 1 }; gbl_general.columnWeights = new double[] { 1.0, 0.1 }; - gbl_general.rowWeights = new double[] { 0.02, 0.0005, 1.0 }; + gbl_general.rowWeights = new double[] { 0.02, 0.0005, 0.02, 0.0005, 1.0 }; setLayout(gbl_general); - GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); - gbc_toggleSwitch.gridx = 1; - gbc_toggleSwitch.gridy = 0; - - add(toggleSwitch, gbc_toggleSwitch); - - if (state == 0) { - onCloseModeState.setText("OFF"); - } else { - onCloseModeState.setText("ON"); - } - - onCloseModeState.setBackground(theme.getCellColor()); - onCloseModeState.setForeground(theme.getUserNameColor()); - - GridBagConstraints gbc_onCloseModeState = new GridBagConstraints(); - gbc_onCloseModeState.anchor = GridBagConstraints.NORTH; - gbc_onCloseModeState.gridx = 1; - gbc_onCloseModeState.gridy = 1; - - add(onCloseModeState, gbc_onCloseModeState); - - onCloseModeText.setText("Client runs in the background, when window is closed"); - onCloseModeText.setBackground(theme.getBackgroundColor()); - // TODO: Change to inverted color. - onCloseModeText.setForeground(theme.getUserNameColor()); - - GridBagConstraints gbc_onCloseModeText = new GridBagConstraints(); - gbc_onCloseModeText.fill = GridBagConstraints.BOTH; - gbc_onCloseModeText.gridx = 0; - gbc_onCloseModeText.gridy = 0; - gbc_onCloseModeText.gridheight = 2; - gbc_onCloseModeText.insets = new Insets(5, 5, 5, 5); - - add(onCloseModeText, gbc_onCloseModeText); - + createSettingElement(0, + "envoy.client.event.OnCloseChangeEvent", + Settings.getInstance().getCurrentOnCloseMode(), + toggleSwitch, + onCloseModeStatePane, + onCloseModeTextPane, + "Client runs in the background, when window is closed"); EventBus.getInstance().register(OnCloseChangeEvent.class, (evt) -> changeOnClose(((OnCloseChangeEvent) evt).get())); + + createSettingElement(2, + "envoy.client.event.EnterToSendEvent", + Settings.getInstance().isEnterToSend(), + toggleSwitchEnterToSend, + enterToSendStatePane, + enterToSendTextPane, + "Press Enter to send messages"); + EventBus.getInstance().register(EnterToSendEvent.class, (evt) -> changeEnterToSend(((EnterToSendEvent) evt).get())); } /** @@ -110,31 +89,105 @@ public class General extends SettingsPanel { * or off. * @since Envoy v0.3-alpha */ - public void changeOnClose(int state) { - System.out.println(state); - this.state = state; + public void changeOnClose(boolean state) { + this.onCloseState = state; - if (state == 0) { - onCloseModeState.setText("OFF"); + if (state == false) { + onCloseModeStatePane.setText("OFF"); } else { - onCloseModeState.setText("ON"); + onCloseModeStatePane.setText("ON"); } this.revalidate(); this.repaint(); } + /** + * This method changes the enter to send a message setting. + * + * @param state This is the integer that defines weather the toggleSwitch is on + * or off. + * @since Envoy v0.3-alpha + */ + public void changeEnterToSend(boolean state) { + this.enterToSend = state; + + if (state == false) { + enterToSendStatePane.setText("OFF"); + } else { + enterToSendStatePane.setText("ON"); + } + this.revalidate(); + this.repaint(); + } + + private void createSettingElement(int gridy, String eventPath, boolean state, PrimaryToggleSwitch toggleSwitch, JTextPane stateText, + JTextPane descriptionText, String text) { + if (state == true) { + toggleSwitch = new PrimaryToggleSwitch(false, eventPath); + } else { + toggleSwitch = new PrimaryToggleSwitch(true, eventPath); + } + + GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); + gbc_toggleSwitch.gridx = 1; + gbc_toggleSwitch.gridy = gridy; + + add(toggleSwitch, gbc_toggleSwitch); + + if (state == false) { + stateText.setText("OFF"); + } else { + stateText.setText("ON"); + } + + stateText.setBackground(theme.getCellColor()); + stateText.setForeground(theme.getUserNameColor()); + + GridBagConstraints gbc_stateText = new GridBagConstraints(); + gbc_stateText.anchor = GridBagConstraints.NORTH; + gbc_stateText.gridx = 1; + gbc_stateText.gridy = gridy + 1; + + add(stateText, gbc_stateText); + + descriptionText.setText(text); + descriptionText.setBackground(theme.getBackgroundColor()); + // TODO: Change to inverted color. + descriptionText.setForeground(theme.getUserNameColor()); + + GridBagConstraints gbc_descriptionText = new GridBagConstraints(); + gbc_descriptionText.fill = GridBagConstraints.BOTH; + gbc_descriptionText.gridx = 0; + gbc_descriptionText.gridy = gridy; + gbc_descriptionText.gridheight = 2; + gbc_descriptionText.insets = new Insets(5, 5, 5, 5); + + add(descriptionText, gbc_descriptionText); + } + @Override public ActionListener getOkButtonAction() { return (evt) -> { - if (state != Settings.getInstance().getCurrentOnCloseMode()) { + if (onCloseState != Settings.getInstance().getCurrentOnCloseMode()) { try { - Settings.getInstance().setCurrentOnCloseMode(state); + Settings.getInstance().setCurrentOnCloseMode(onCloseState); JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); } catch (Exception e) { logger.info("Close mode could not be changed! " + e); e.printStackTrace(); } } + + if (enterToSend != Settings.getInstance().isEnterToSend()) { + try { + Settings.getInstance().setEnterToSend(enterToSend); + ; + JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); + } catch (Exception e) { + logger.info("Enter to send mode could not be changed! " + e); + e.printStackTrace(); + } + } }; } From 4a4c4f9308d0da7c85fdeb4c690569194d6a20b8 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Dec 2019 10:56:33 +0100 Subject: [PATCH 155/474] Fixed formatting, Javadoc and other cosmetic problems Also fixed PrimaryToggleSwitches having editable text in their state and description fields --- .../envoy/client/event/EnterToSendEvent.java | 12 +- .../client/event/OnCloseChangeEvent.java | 13 +-- .../envoy/client/ui/PrimaryToggleSwitch.java | 71 +++++------- src/main/java/envoy/client/ui/Startup.java | 8 +- .../envoy/client/ui/settings/General.java | 104 +++++++----------- .../ui/settings/ThemeCustomizationPanel.java | 4 +- 6 files changed, 85 insertions(+), 127 deletions(-) diff --git a/src/main/java/envoy/client/event/EnterToSendEvent.java b/src/main/java/envoy/client/event/EnterToSendEvent.java index f96d13e..7b26e0a 100644 --- a/src/main/java/envoy/client/event/EnterToSendEvent.java +++ b/src/main/java/envoy/client/event/EnterToSendEvent.java @@ -1,6 +1,8 @@ package envoy.client.event; /** + * Encapsulates a change to the {@code enterToSend} setting.
+ *
* Project: envoy-client
* File: EnterToSendEvent.java
* Created: 22 Dec 2019
@@ -13,15 +15,13 @@ public class EnterToSendEvent implements Event { private boolean mode; /** - * @param mode This is the enter to sent mode when sending messages. - *
- * true = Enter to Send Messages
- * false = Enter to do a line break + * Initializes an {@link EnterToSendEvent}. + * + * @param mode the state of the {@code enterToSend} setting * @since Envoy 0.3-alpha */ public EnterToSendEvent(boolean mode) { this.mode = mode; } @Override public Boolean get() { return mode; } - -} +} \ No newline at end of file diff --git a/src/main/java/envoy/client/event/OnCloseChangeEvent.java b/src/main/java/envoy/client/event/OnCloseChangeEvent.java index 717a5da..2d86fb6 100644 --- a/src/main/java/envoy/client/event/OnCloseChangeEvent.java +++ b/src/main/java/envoy/client/event/OnCloseChangeEvent.java @@ -1,6 +1,8 @@ package envoy.client.event; /** + * Encapsulates a change to the {@code currentOnCloseMode} setting.
+ *
* Project: envoy-client
* File: OnCloseChangeEvent.java
* Created: 22 Dec 2019
@@ -13,16 +15,13 @@ public class OnCloseChangeEvent implements Event { private boolean closeMode; /** - * @param closeMode This is the on close mode for the client, that should be - * set. - *
- * true = ExitOnClose
- * false = HideOnClose + * Initializes an {@link OnCloseChangeEvent}. + * + * @param closeMode the state of the {@code currentOnCloseMode} setting * @since Envoy 0.3-alpha */ public OnCloseChangeEvent(boolean closeMode) { this.closeMode = closeMode; } @Override public Boolean get() { return closeMode; } - -} +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 361db5d..109656a 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -4,7 +4,8 @@ import java.awt.*; import java.lang.reflect.Constructor; import java.util.logging.Logger; -import javax.swing.*; +import javax.swing.JButton; +import javax.swing.JPanel; import envoy.client.Settings; import envoy.client.event.Event; @@ -12,10 +13,9 @@ import envoy.client.event.EventBus; import envoy.client.util.EnvoyLog; /** - * This Component can be used to toggle between two options. e.g. on and off - *
- *
- * + * This Component can be used to toggle between two options. e.g. on and + * off.
+ *
* Project: envoy-client
* File: PrimaryToggleSwitch.java
* Created: 21 Dec 2019
@@ -25,11 +25,12 @@ import envoy.client.util.EnvoyLog; */ public class PrimaryToggleSwitch extends JPanel { - private static final long serialVersionUID = -721155303106833184L; - JButton b = new JButton(""); - private boolean currentState; - private boolean variable; + private final JButton b = new JButton(""); + private boolean currentState; + private boolean variable; + private static final Logger logger = EnvoyLog.getLogger(PrimaryToggleSwitch.class.getSimpleName()); + private static final long serialVersionUID = -721155303106833184L; /** * This is the constructor for the PrimaryToggleSwitch. @@ -37,12 +38,10 @@ public class PrimaryToggleSwitch extends JPanel { * @param initialState The state the toggleSwitch is standardly set to.
* true: off
* false: on - * @param eventName the path of the event class + * @param eventClass the class of the event dispatched by this toggleSwitch * @since Envoy v0.3-alpha */ - @SuppressWarnings({ "rawtypes", "unused" }) - public PrimaryToggleSwitch(boolean initialState, String eventName) { - super(); + public PrimaryToggleSwitch(boolean initialState, Class> eventClass) { setEnabled(true); setVisible(true); @@ -68,26 +67,22 @@ public class PrimaryToggleSwitch extends JPanel { b.addActionListener((evt) -> { try { - Class c = Class.forName(eventName); - Class[] types = { boolean.class }; - Constructor constructor = c.getConstructor(types); + // Dispatch event + Constructor> constructor = eventClass.getConstructor(boolean.class); + EventBus.getInstance().dispatch((Event) constructor.newInstance(variable)); - Object[] parameters = { variable }; - Object instanceOfC = constructor.newInstance(parameters); - - EventBus.getInstance().dispatch((Event) constructor.newInstance(parameters)); setState(!currentState); - this.revalidate(); - this.repaint(); - } catch (Exception e) { - logger.info("An error occured while changing the setting: " + e); - e.printStackTrace(); + revalidate(); + repaint(); + } catch (ReflectiveOperationException | SecurityException e) { + logger.warning("An error occured while changing the setting: " + e); } }); repaint(); } + @Override public void paintComponent(Graphics g) { g.setColor(Color.LIGHT_GRAY); g.fillRect(0, 0, 50, 25); @@ -96,33 +91,25 @@ public class PrimaryToggleSwitch extends JPanel { } /** - * This method sets the state of the {@link PrimaryToggleSwitch}. + * This method sets the state of this {@link PrimaryToggleSwitch}. * - * @param state This is the state of the {@link PrimaryToggleSwitch}, that - * should be set.
- * true: off
- * false: on + * @param state {@code true} to enable the switch, {@code false} to disable it * @since Envoy 0.3-alpha */ public void setState(boolean state) { + GridBagConstraints gbc_toggleButton = new GridBagConstraints(); + if (state) { - GridBagConstraints gbc_toggleButton = new GridBagConstraints(); gbc_toggleButton.anchor = GridBagConstraints.WEST; gbc_toggleButton.gridx = 0; - gbc_toggleButton.gridy = 0; - - add(b, gbc_toggleButton); - currentState = true; - variable = true; } else { - GridBagConstraints gbc_toggleButton = new GridBagConstraints(); gbc_toggleButton.anchor = GridBagConstraints.EAST; gbc_toggleButton.gridx = 1; - gbc_toggleButton.gridy = 0; - - add(b, gbc_toggleButton); - currentState = false; - variable = false; } + gbc_toggleButton.gridy = 0; + add(b, gbc_toggleButton); + + currentState = state; + variable = state; } } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index d2f7125..9cce0dd 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -131,13 +131,9 @@ public class Startup { try { new StatusTrayIcon(chatWindow).show(); - // If the tray icon is supported, hide the chat window on close - if (Settings.getInstance().getCurrentOnCloseMode() == true) { + // If the tray icon is supported and corresponding settings is set, hide the chat window on close + if (Settings.getInstance().getCurrentOnCloseMode()) chatWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - } else { - chatWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - } - } catch (EnvoyException e) { logger.warning("The StatusTrayIcon is not supported on this platform!"); } diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java index e922359..faa46bc 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -4,15 +4,14 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionListener; +import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; import javax.swing.JTextPane; import envoy.client.Settings; -import envoy.client.event.EnterToSendEvent; -import envoy.client.event.EventBus; -import envoy.client.event.OnCloseChangeEvent; +import envoy.client.event.*; import envoy.client.ui.PrimaryToggleSwitch; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; @@ -20,7 +19,6 @@ import envoy.client.util.EnvoyLog; /** * Displays GUI components that allow general settings regarding the client.
*
- * * Project: envoy-client
* File: General.java
* Created: 21 Dec 2019
@@ -30,19 +28,20 @@ import envoy.client.util.EnvoyLog; */ public class General extends SettingsPanel { - private static final long serialVersionUID = -7470848775130754239L; + private Theme theme; + private boolean onCloseState; + private boolean enterToSend; + + private PrimaryToggleSwitch toggleSwitch; + private JTextPane onCloseModeTextPane = new JTextPane(); + private JTextPane onCloseModeStatePane = new JTextPane(); + + private PrimaryToggleSwitch toggleSwitchEnterToSend; + private JTextPane enterToSendTextPane = new JTextPane(); + private JTextPane enterToSendStatePane = new JTextPane(); + private static final Logger logger = EnvoyLog.getLogger(General.class.getSimpleName()); - private Theme theme; - private boolean onCloseState; - private boolean enterToSend; - - PrimaryToggleSwitch toggleSwitch; - JTextPane onCloseModeTextPane = new JTextPane(); - JTextPane onCloseModeStatePane = new JTextPane(); - - PrimaryToggleSwitch toggleSwitchEnterToSend; - JTextPane enterToSendTextPane = new JTextPane(); - JTextPane enterToSendStatePane = new JTextPane(); + private static final long serialVersionUID = -7470848775130754239L; /** * This is the constructor for the General class. Here the user can set general @@ -64,7 +63,7 @@ public class General extends SettingsPanel { setLayout(gbl_general); createSettingElement(0, - "envoy.client.event.OnCloseChangeEvent", + OnCloseChangeEvent.class, Settings.getInstance().getCurrentOnCloseMode(), toggleSwitch, onCloseModeStatePane, @@ -73,7 +72,7 @@ public class General extends SettingsPanel { EventBus.getInstance().register(OnCloseChangeEvent.class, (evt) -> changeOnClose(((OnCloseChangeEvent) evt).get())); createSettingElement(2, - "envoy.client.event.EnterToSendEvent", + EnterToSendEvent.class, Settings.getInstance().isEnterToSend(), toggleSwitchEnterToSend, enterToSendStatePane, @@ -92,13 +91,9 @@ public class General extends SettingsPanel { public void changeOnClose(boolean state) { this.onCloseState = state; - if (state == false) { - onCloseModeStatePane.setText("OFF"); - } else { - onCloseModeStatePane.setText("ON"); - } - this.revalidate(); - this.repaint(); + onCloseModeStatePane.setText(state ? "ON" : "OFF"); + revalidate(); + repaint(); } /** @@ -111,22 +106,14 @@ public class General extends SettingsPanel { public void changeEnterToSend(boolean state) { this.enterToSend = state; - if (state == false) { - enterToSendStatePane.setText("OFF"); - } else { - enterToSendStatePane.setText("ON"); - } - this.revalidate(); - this.repaint(); + enterToSendStatePane.setText(state ? "ON" : "OFF"); + revalidate(); + repaint(); } - private void createSettingElement(int gridy, String eventPath, boolean state, PrimaryToggleSwitch toggleSwitch, JTextPane stateText, - JTextPane descriptionText, String text) { - if (state == true) { - toggleSwitch = new PrimaryToggleSwitch(false, eventPath); - } else { - toggleSwitch = new PrimaryToggleSwitch(true, eventPath); - } + private void createSettingElement(int gridy, Class> eventClass, boolean state, PrimaryToggleSwitch toggleSwitch, + JTextPane stateText, JTextPane descriptionText, String text) { + toggleSwitch = new PrimaryToggleSwitch(state, eventClass); GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); gbc_toggleSwitch.gridx = 1; @@ -134,14 +121,10 @@ public class General extends SettingsPanel { add(toggleSwitch, gbc_toggleSwitch); - if (state == false) { - stateText.setText("OFF"); - } else { - stateText.setText("ON"); - } - + stateText.setText(state ? "ON" : "OFF"); stateText.setBackground(theme.getCellColor()); stateText.setForeground(theme.getUserNameColor()); + stateText.setEditable(false); GridBagConstraints gbc_stateText = new GridBagConstraints(); gbc_stateText.anchor = GridBagConstraints.NORTH; @@ -154,6 +137,7 @@ public class General extends SettingsPanel { descriptionText.setBackground(theme.getBackgroundColor()); // TODO: Change to inverted color. descriptionText.setForeground(theme.getUserNameColor()); + descriptionText.setEditable(false); GridBagConstraints gbc_descriptionText = new GridBagConstraints(); gbc_descriptionText.fill = GridBagConstraints.BOTH; @@ -168,27 +152,19 @@ public class General extends SettingsPanel { @Override public ActionListener getOkButtonAction() { return (evt) -> { - if (onCloseState != Settings.getInstance().getCurrentOnCloseMode()) { - try { - Settings.getInstance().setCurrentOnCloseMode(onCloseState); - JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); - } catch (Exception e) { - logger.info("Close mode could not be changed! " + e); - e.printStackTrace(); - } + if (onCloseState != Settings.getInstance().getCurrentOnCloseMode()) try { + Settings.getInstance().setCurrentOnCloseMode(onCloseState); + JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); + } catch (Exception e) { + logger.log(Level.WARNING, "Close mode could not be changed! ", e); } - if (enterToSend != Settings.getInstance().isEnterToSend()) { - try { - Settings.getInstance().setEnterToSend(enterToSend); - ; - JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); - } catch (Exception e) { - logger.info("Enter to send mode could not be changed! " + e); - e.printStackTrace(); - } + if (enterToSend != Settings.getInstance().isEnterToSend()) try { + Settings.getInstance().setEnterToSend(enterToSend); + JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); + } catch (Exception e) { + logger.log(Level.WARNING, "Enter to send mode could not be changed! ", e); } }; } - -} +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 959690e..5310a5e 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -30,7 +30,6 @@ import envoy.client.util.EnvoyLog; */ public class ThemeCustomizationPanel extends SettingsPanel { - private static final long serialVersionUID = -8697897390666456624L; private JPanel colorsPanel = new JPanel(); @@ -42,6 +41,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { private final Insets insets = new Insets(5, 5, 5, 5); private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class.getSimpleName()); + private static final long serialVersionUID = -8697897390666456624L; /** * Initializes a {@link ThemeCustomizationPanel} that enables the user to change @@ -230,4 +230,4 @@ public class ThemeCustomizationPanel extends SettingsPanel { } private Color getInvertedColor(Color color) { return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); } -} +} \ No newline at end of file From 728b54080ca2841e30cece0da7797a4ee813c87d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Dec 2019 11:28:00 +0100 Subject: [PATCH 156/474] Added custom Color class to envoy.ui with invert() and toHex() methods. --- src/main/java/envoy/client/Settings.java | 4 +- src/main/java/envoy/client/ui/Color.java | 106 ++++++++++++++++++ .../envoy/client/ui/MessageListRenderer.java | 13 +-- .../envoy/client/ui/PrimaryToggleSwitch.java | 11 +- src/main/java/envoy/client/ui/Theme.java | 1 - .../envoy/client/ui/UserListRenderer.java | 11 +- .../envoy/client/ui/settings/General.java | 3 +- .../client/ui/settings/SettingsScreen.java | 12 +- .../ui/settings/ThemeCustomizationPanel.java | 10 +- 9 files changed, 127 insertions(+), 44 deletions(-) create mode 100644 src/main/java/envoy/client/ui/Color.java diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 5e15743..fc60877 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -1,11 +1,11 @@ package envoy.client; -import java.awt.Color; import java.io.*; import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; +import envoy.client.ui.Color; import envoy.client.ui.Theme; /** @@ -28,7 +28,7 @@ public class Settings { private boolean enterToSend = true; private Map themes; private String currentTheme; - private boolean currentOnCloseMode; + private boolean currentOnCloseMode; /** * Required to save the settings. diff --git a/src/main/java/envoy/client/ui/Color.java b/src/main/java/envoy/client/ui/Color.java new file mode 100644 index 0000000..33be64b --- /dev/null +++ b/src/main/java/envoy/client/ui/Color.java @@ -0,0 +1,106 @@ +package envoy.client.ui; + +import java.awt.color.ColorSpace; + +/** + * Project: envoy-clientChess
+ * File: Color.javaEvent.java
+ * Created: 23.12.2019
+ * + * @author Kai S. K. Engelbart + */ +@SuppressWarnings("javadoc") +public class Color extends java.awt.Color { + + /** + * The color white. In the default sRGB space. + */ + public static final Color white = new Color(255, 255, 255); + + /** + * The color light gray. In the default sRGB space. + */ + public static final Color lightGray = new Color(192, 192, 192); + + /** + * The color gray. In the default sRGB space. + */ + public static final Color gray = new Color(128, 128, 128); + + /** + * The color dark gray. In the default sRGB space. + */ + public static final Color darkGray = new Color(64, 64, 64); + + /** + * The color black. In the default sRGB space. + */ + public static final Color black = new Color(0, 0, 0); + + /** + * The color red. In the default sRGB space. + */ + public static final Color red = new Color(255, 0, 0); + + /** + * The color pink. In the default sRGB space. + */ + public static final Color pink = new Color(255, 175, 175); + + /** + * The color orange. In the default sRGB space. + */ + public static final Color orange = new Color(255, 200, 0); + + /** + * The color yellow. In the default sRGB space. + */ + public static final Color yellow = new Color(255, 255, 0); + + /** + * The color green. In the default sRGB space. + */ + public static final Color green = new Color(0, 255, 0); + + /** + * The color magenta. In the default sRGB space. + */ + public static final Color magenta = new Color(255, 0, 255); + + /** + * The color cyan. In the default sRGB space. + */ + public static final Color cyan = new Color(0, 255, 255); + + /** + * The color blue. In the default sRGB space. + */ + public static final Color blue = new Color(0, 0, 255); + + private static final long serialVersionUID = -9166233199998257344L; + + public Color(int rgb) { super(rgb); } + + public Color(int rgba, boolean hasalpha) { super(rgba, hasalpha); } + + public Color(int r, int g, int b) { super(r, g, b); } + + public Color(float r, float g, float b) { super(r, g, b); } + + public Color(ColorSpace cspace, float[] components, float alpha) { super(cspace, components, alpha); } + + public Color(int r, int g, int b, int a) { super(r, g, b, a); } + + public Color(float r, float g, float b, float a) { super(r, g, b, a); } + + /** + * @return the inversion of this {@link Color} by replacing the red, green and + * blue values by subtracting them form 255 + */ + public Color invert() { return new Color(255 - getRed(), 255 - getGreen(), 255 - getBlue()); } + + /** + * @return the hex value of this {@link Color} + */ + public String toHex() { return String.format("#%02x%02x%02x", getRed(), getGreen(), getBlue()); } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 5623fb6..ddd2230 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -1,6 +1,5 @@ package envoy.client.ui; -import java.awt.Color; import java.awt.Component; import java.text.SimpleDateFormat; @@ -46,11 +45,11 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer

%s

%s :%s", dateColor, @@ -60,12 +59,4 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer> constructor = eventClass.getConstructor(boolean.class); - EventBus.getInstance().dispatch((Event) constructor.newInstance(variable)); + EventBus.getInstance().dispatch(constructor.newInstance(currentState)); setState(!currentState); revalidate(); @@ -109,7 +109,6 @@ public class PrimaryToggleSwitch extends JPanel { gbc_toggleButton.gridy = 0; add(b, gbc_toggleButton); - currentState = state; - variable = state; + currentState = state; } } diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index 3e6c39e..d912988 100644 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -1,6 +1,5 @@ package envoy.client.ui; -import java.awt.Color; import java.io.Serializable; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index d26aa8b..ca7214d 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -1,6 +1,5 @@ package envoy.client.ui; -import java.awt.Color; import java.awt.Component; import javax.swing.JLabel; @@ -44,7 +43,7 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { // Getting the UserNameColor of the current theme String textColor = null; - textColor = toHex(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor()); + textColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor().toHex(); switch (status) { case ONLINE: setText(String @@ -57,12 +56,4 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { } return this; } - - private String toHex(Color c) { - int r = c.getRed(); - int g = c.getGreen(); - int b = c.getBlue(); - String hex = String.format("#%02x%02x%02x", r, g, b); - return hex; - } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java index faa46bc..b128454 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -134,8 +134,7 @@ public class General extends SettingsPanel { add(stateText, gbc_stateText); descriptionText.setText(text); - descriptionText.setBackground(theme.getBackgroundColor()); - // TODO: Change to inverted color. + descriptionText.setBackground(theme.getBackgroundColor().invert()); descriptionText.setForeground(theme.getUserNameColor()); descriptionText.setEditable(false); diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index d0e4b8f..b971625 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -39,7 +39,7 @@ public class SettingsScreen extends JDialog { private final JList options = new JList<>(optionsListModel); // OK and cancel buttons - private final JPanel buttonPane = new JPanel(); + private final JPanel buttonPane = new JPanel(); private final PrimaryButton okButton = new PrimaryButton("Save"); private final PrimaryButton cancelButton = new PrimaryButton("Cancel"); @@ -119,10 +119,10 @@ public class SettingsScreen extends JDialog { // ButtonPane GridBagLayout gbl_buttonPane = new GridBagLayout(); - gbl_buttonPane.columnWidths = new int[] { 1, 1}; - gbl_buttonPane.rowHeights = new int[] { 25}; - gbl_buttonPane.columnWeights = new double[] { 1.0, 1.0}; - gbl_buttonPane.rowWeights = new double[] { 0.0}; + gbl_buttonPane.columnWidths = new int[] { 1, 1 }; + gbl_buttonPane.rowHeights = new int[] { 25 }; + gbl_buttonPane.columnWeights = new double[] { 1.0, 1.0 }; + gbl_buttonPane.rowWeights = new double[] { 0.0 }; getContentPane().add(buttonPane, BorderLayout.SOUTH); buttonPane.setLayout(gbl_buttonPane); @@ -189,4 +189,4 @@ public class SettingsScreen extends JDialog { options.setForeground(theme.getUserNameColor()); options.setBackground(theme.getCellColor()); } -} +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 5310a5e..8c3f9f4 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -13,6 +13,7 @@ import javax.swing.*; import envoy.client.Settings; import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; +import envoy.client.ui.Color; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; @@ -30,7 +31,6 @@ import envoy.client.util.EnvoyLog; */ public class ThemeCustomizationPanel extends SettingsPanel { - private JPanel colorsPanel = new JPanel(); private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]); @@ -40,7 +40,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { private final Insets insets = new Insets(5, 5, 5, 5); - private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class.getSimpleName()); private static final long serialVersionUID = -8697897390666456624L; /** @@ -185,7 +185,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { textPane.setFont(new Font("Arial", Font.PLAIN, 14)); textPane.setBackground(theme.getBackgroundColor()); - textPane.setForeground(getInvertedColor(theme.getBackgroundColor())); + textPane.setForeground(theme.getBackgroundColor().invert()); textPane.setText(name); textPane.setEditable(false); @@ -194,7 +194,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { button.addActionListener((evt) -> { try { - Color newColor = JColorChooser.showDialog(null, "Choose a color", color); + Color newColor = (Color) JColorChooser.showDialog(null, "Choose a color", color); if (newColor.getRGB() != color.getRGB()) { logger.log(Level.FINEST, "New Color: " + String.valueOf(color.getRGB())); // TODO: When Theme changed in same settings screen, color variable doesn't @@ -228,6 +228,4 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.add(button, gbc_button); } - - private Color getInvertedColor(Color color) { return new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()); } } \ No newline at end of file From 035b3c02e4cc0bc79f80ce1140c2b23cb2b482b5 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Dec 2019 14:25:46 +0100 Subject: [PATCH 157/474] Saving settings in a file, added SettingsItem class --- src/main/java/envoy/client/LocalDB.java | 45 ++----- src/main/java/envoy/client/Settings.java | 112 +++++++++--------- src/main/java/envoy/client/SettingsItem.java | 87 ++++++++++++++ .../envoy/client/ui/settings/General.java | 8 +- .../envoy/client/util/SerializationUtils.java | 38 ++++++ 5 files changed, 198 insertions(+), 92 deletions(-) create mode 100644 src/main/java/envoy/client/SettingsItem.java create mode 100644 src/main/java/envoy/client/util/SerializationUtils.java diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 7db7200..b5e3971 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -1,6 +1,7 @@ package envoy.client; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.time.Instant; import java.util.*; import java.util.logging.Logger; @@ -11,6 +12,7 @@ import javax.xml.datatype.DatatypeFactory; import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; import envoy.client.util.EnvoyLog; +import envoy.client.util.SerializationUtils; import envoy.exception.EnvoyException; import envoy.schema.*; import envoy.schema.Message.Metadata.MessageState; @@ -38,7 +40,7 @@ public class LocalDB { private Sync sync = objectFactory.createSync(); private Sync readMessages = objectFactory.createSync(); - private static final Logger logger = EnvoyLog.getLogger(LocalDB.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(LocalDB.class.getSimpleName()); /** * Constructs an empty local database. To serialize any chats to the file @@ -83,10 +85,10 @@ public class LocalDB { */ public void save() throws IOException { // Save users - write(usersFile, users); + SerializationUtils.write(usersFile, users); // Save chats - write(localDBFile, chats); + SerializationUtils.write(localDBFile, chats); } /** @@ -95,8 +97,7 @@ public class LocalDB { * @throws EnvoyException if the loading process failed * @since Envoy v0.2-alpha */ - @SuppressWarnings("unchecked") - public void loadUsers() throws EnvoyException { users = read(usersFile, HashMap.class); } + public void loadUsers() throws EnvoyException { users = SerializationUtils.read(usersFile, HashMap.class); } /** * Loads all chats saved by Envoy for the client user. @@ -104,31 +105,7 @@ public class LocalDB { * @throws EnvoyException if the loading process failed * @since Envoy v0.1-alpha */ - @SuppressWarnings("unchecked") - public void loadChats() throws EnvoyException { chats = read(localDBFile, ArrayList.class); } - - private T read(File file, Class serializedClass) throws EnvoyException { - if (file == null) throw new NullPointerException("File is null"); - try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { - return serializedClass.cast(in.readObject()); - } catch (ClassNotFoundException | IOException e) { - throw new EnvoyException("Could not load serialized object", e); - } - } - - private void write(File file, T obj) throws IOException { - if (file == null) throw new NullPointerException("File is null"); - if (obj == null) throw new NullPointerException("Object to serialize is null"); - if (!file.exists()) { - file.getParentFile().mkdirs(); - file.createNewFile(); - } - try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) { - out.writeObject(obj); - } catch (IOException e) { - throw e; - } - } + public void loadChats() throws EnvoyException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } /** * Creates a {@link Message} object serializable to XML. @@ -238,8 +215,7 @@ public class LocalDB { // Updating UserStatus of all users in LocalDB for (User user : returnSync.getUsers()) for (Chat chat : getChats()) - if (user.getID() == chat.getRecipient().getID()) - chat.getRecipient().setStatus(user.getStatus()); + if (user.getID() == chat.getRecipient().getID()) chat.getRecipient().setStatus(user.getStatus()); sync.getMessages().clear(); sync.getUsers().clear(); @@ -301,7 +277,8 @@ public class LocalDB { public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } /** - * @return a {@code Map} of all users stored locally with their user names as keys + * @return a {@code Map} of all users stored locally with their + * user names as keys * @since Envoy v0.2-alpha */ public Map getUsers() { return users; } diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index fc60877..e79596c 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -7,6 +7,8 @@ import java.util.prefs.Preferences; import envoy.client.ui.Color; import envoy.client.ui.Theme; +import envoy.client.util.SerializationUtils; +import envoy.exception.EnvoyException; /** * Manages all application settings, which are different objects that can be @@ -25,20 +27,18 @@ import envoy.client.ui.Theme; public class Settings { // Actual settings accessible by the rest of the application - private boolean enterToSend = true; - private Map themes; - private String currentTheme; - private boolean currentOnCloseMode; + private Map> items; + private Map themes; /** - * Required to save the settings. + * Settings are stored in this file. */ - private Preferences prefs = Preferences.userNodeForPackage(Settings.class); + private static final File settingsFile = new File(Config.getInstance().getHomeDirectory(), "settings.ser"); /** * User-defined themes are stored inside this file. */ - private File themeFile = new File(Config.getInstance().getHomeDirectory(), "themes.ser"); + private static final File themeFile = new File(Config.getInstance().getHomeDirectory(), "themes.ser"); /** * Singleton instance of this class. @@ -51,30 +51,21 @@ public class Settings { * * @since Envoy v0.2-alpha */ - private Settings() { load(); } - - /** - * This method is used to ensure that there is only one instance of Settings. - * - * @return the instance of Settings - * @since Envoy v0.2-alpha - */ - public static Settings getInstance() { return settings; } - - @SuppressWarnings("unchecked") - private void load() { - setEnterToSend(prefs.getBoolean("enterToSend", true)); - setCurrentTheme(prefs.get("theme", "dark")); - setCurrentOnCloseMode(prefs.getBoolean("onCloseMode", true)); + private Settings() { + // Load settings from settings file + try { + items = SerializationUtils.read(settingsFile, HashMap.class); + } catch (EnvoyException e) { + items = new HashMap<>(); + } + supplementDefaults(); // Load themes from theme file - try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) { - Object obj = in.readObject(); - if (obj instanceof HashMap) themes = (Map) obj; - } catch (IOException | ClassNotFoundException e) { - themes = new HashMap<>(); - currentTheme = "dark"; - e.printStackTrace(); + try { + themes = SerializationUtils.read(themeFile, HashMap.class); + } catch (EnvoyException e1) { + themes = new HashMap<>(); + setCurrentTheme("dark"); } // Load standard themes not defined in the themes file @@ -86,6 +77,14 @@ public class Settings { Color.black, Color.black)); } + /** + * This method is used to ensure that there is only one instance of Settings. + * + * @return the instance of Settings + * @since Envoy v0.2-alpha + */ + public static Settings getInstance() { return settings; } + /** * Updates the preferences when the save button is clicked. * @@ -94,15 +93,17 @@ public class Settings { * @since Envoy v0.2-alpha */ public void save() throws IOException { - prefs.put("theme", currentTheme); - prefs.putBoolean("enterToSend", isEnterToSend()); - prefs.putBoolean("onCloseMode", currentOnCloseMode); + // Save settings to settings file + SerializationUtils.write(settingsFile, items); // Save themes to theme file - themeFile.createNewFile(); - try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) { - out.writeObject(themes); - } + SerializationUtils.write(themeFile, themes); + } + + private void supplementDefaults() { + items.putIfAbsent("enterToSend", new SettingsItem<>(true, "Enter to send", "Sends a message by pressing the enter key.")); + items.putIfAbsent("onCloseMode", new SettingsItem<>(false, "Hide on close", "Hides the chat window when it is closed.")); + items.putIfAbsent("currentTheme", new SettingsItem<>("dark", null)); } /** @@ -117,7 +118,7 @@ public class Settings { * @return the name of the currently active {@link Theme} * @since Envoy v0.2-alpha */ - public String getCurrentTheme() { return currentTheme; } + public String getCurrentTheme() { return (String) items.get("currentTheme").get(); } /** * Sets the name of the current {@link Theme}. @@ -125,7 +126,8 @@ public class Settings { * @param themeName the name to set * @since Envoy v0.2-alpha */ - public void setCurrentTheme(String themeName) { currentTheme = themeName; } + @SuppressWarnings("unchecked") + public void setCurrentTheme(String themeName) { ((SettingsItem) items.get("currentTheme")).set(themeName); } /** * @return {@code true}, if pressing the {@code Enter} key suffices to send a @@ -133,7 +135,7 @@ public class Settings { * {@code Control} key. * @since Envoy v0.2-alpha */ - public boolean isEnterToSend() { return enterToSend; } + public boolean isEnterToSend() { return (boolean) items.get("enterToSend").get(); } /** * Changes the keystrokes performed by the user to send a message. @@ -143,7 +145,23 @@ public class Settings { * conjunction with the {@code Control} key. * @since Envoy v0.2-alpha */ - public void setEnterToSend(boolean enterToSend) { this.enterToSend = enterToSend; } + @SuppressWarnings("unchecked") + public void setEnterToSend(boolean enterToSend) { ((SettingsItem) items.get("enterToSend")).set(enterToSend); } + + /** + * @return the current on close mode. + * @since Envoy v0.3-alpha + */ + public boolean getCurrentOnCloseMode() { return (boolean) items.get("onCloseMode").get(); } + + /** + * Sets the current on close mode. + * + * @param currentOnCloseMode the on close mode that should be set. + * @since Envoy v0.3-alpha + */ + @SuppressWarnings("unchecked") + public void setCurrentOnCloseMode(boolean currentOnCloseMode) { ((SettingsItem) items.get("onCloseMode")).set(currentOnCloseMode); } /** * @return a {@code Map} of all themes with their names as keys @@ -158,18 +176,4 @@ public class Settings { * @since Envoy v0.2-alpha */ public void setThemes(Map themes) { this.themes = themes; } - - /** - * @return the current on close mode. - * @since Envoy v0.3-alpha - */ - public boolean getCurrentOnCloseMode() { return currentOnCloseMode; } - - /** - * Sets the current on close mode. - * - * @param currentOnCloseMode the on close mode that should be set. - * @since Envoy v0.3-alpha - */ - public void setCurrentOnCloseMode(boolean currentOnCloseMode) { this.currentOnCloseMode = currentOnCloseMode; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/SettingsItem.java b/src/main/java/envoy/client/SettingsItem.java new file mode 100644 index 0000000..23da76a --- /dev/null +++ b/src/main/java/envoy/client/SettingsItem.java @@ -0,0 +1,87 @@ +package envoy.client; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.JComponent; + +import envoy.client.ui.PrimaryToggleSwitch; + +/** + * Project: envoy-clientChess
+ * File: SettingsItem.java
+ * Created: 23.12.2019
+ * + * @author Kai S. K. Engelbart + */ +public class SettingsItem implements Serializable { + + private T value; + private Class componentClass; + private String userFriendlyName, description; + + private static final Map, Class> componentClasses = new HashMap<>(); + + private static final long serialVersionUID = 2146837835556852218L; + + static { + componentClasses.put(boolean.class, PrimaryToggleSwitch.class); + } + + public SettingsItem(T value, String userFriendlyName, String description) { + this(value, componentClasses.get(value.getClass())); + this.userFriendlyName = userFriendlyName; + this.description = description; + } + + public SettingsItem(T value, Class componentClass) { + this.value = value; + this.componentClass = componentClass; + } + + public JComponent getComponent() throws ReflectiveOperationException, SecurityException { + if (componentClass == null) throw new NullPointerException("Component class is null"); + return componentClass.getConstructor(SettingsItem.class).newInstance(this); + } + + /** + * @return the value + */ + public T get() { return value; } + + /** + * @param value the value to set + */ + public void set(T value) { this.value = value; } + + /** + * @return the componentClass + */ + public Class getComponentClass() { return componentClass; } + + /** + * @param componentClass the componentClass to set + */ + public void setComponentClass(Class componentClass) { this.componentClass = componentClass; } + + /** + * @return the userFriendlyName + */ + public String getUserFriendlyName() { return userFriendlyName; } + + /** + * @param userFriendlyName the userFriendlyName to set + */ + public void setUserFriendlyName(String userFriendlyName) { this.userFriendlyName = userFriendlyName; } + + /** + * @return the description + */ + public String getDescription() { return description; } + + /** + * @param description the description to set + */ + public void setDescription(String description) { this.description = description; } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java index b128454..235cee9 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -29,8 +29,8 @@ import envoy.client.util.EnvoyLog; public class General extends SettingsPanel { private Theme theme; - private boolean onCloseState; - private boolean enterToSend; + private boolean onCloseState = Settings.getInstance().getCurrentOnCloseMode(); + private boolean enterToSend = Settings.getInstance().isEnterToSend(); private PrimaryToggleSwitch toggleSwitch; private JTextPane onCloseModeTextPane = new JTextPane(); @@ -134,8 +134,8 @@ public class General extends SettingsPanel { add(stateText, gbc_stateText); descriptionText.setText(text); - descriptionText.setBackground(theme.getBackgroundColor().invert()); - descriptionText.setForeground(theme.getUserNameColor()); + descriptionText.setBackground(theme.getBackgroundColor()); + descriptionText.setForeground(theme.getBackgroundColor().invert()); descriptionText.setEditable(false); GridBagConstraints gbc_descriptionText = new GridBagConstraints(); diff --git a/src/main/java/envoy/client/util/SerializationUtils.java b/src/main/java/envoy/client/util/SerializationUtils.java new file mode 100644 index 0000000..5a4b842 --- /dev/null +++ b/src/main/java/envoy/client/util/SerializationUtils.java @@ -0,0 +1,38 @@ +package envoy.client.util; + +import java.io.*; + +import envoy.exception.EnvoyException; + +/** + * Project: envoy-clientChess
+ * File: SerializationUtils.javaEvent.java
+ * Created: 23.12.2019
+ * + * @author Kai S. K. Engelbart + */ +public class SerializationUtils { + + private SerializationUtils() {} + + public static T read(File file, Class serializedClass) throws EnvoyException { + if (file == null) throw new NullPointerException("File is null"); + try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { + return serializedClass.cast(in.readObject()); + } catch (ClassNotFoundException | IOException e) { + throw new EnvoyException("Could not load serialized object", e); + } + } + + public static void write(File file, Object obj) throws IOException { + if (file == null) throw new NullPointerException("File is null"); + if (obj == null) throw new NullPointerException("Object to serialize is null"); + if (!file.exists()) { + file.getParentFile().mkdirs(); + file.createNewFile(); + } + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) { + out.writeObject(obj); + } + } +} From 3d381f4351bda818d97fbec92ab8fb3e8627831a Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Dec 2019 14:51:52 +0100 Subject: [PATCH 158/474] Adjusting PrimaryToggleSwitch implementation to SettingsItem class --- src/main/java/envoy/client/Settings.java | 10 ++++ .../envoy/client/ui/PrimaryToggleSwitch.java | 35 ++++---------- .../envoy/client/ui/settings/General.java | 48 +++++++------------ 3 files changed, 36 insertions(+), 57 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index e79596c..9732248 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -163,6 +163,16 @@ public class Settings { @SuppressWarnings("unchecked") public void setCurrentOnCloseMode(boolean currentOnCloseMode) { ((SettingsItem) items.get("onCloseMode")).set(currentOnCloseMode); } + /** + * @return the items + */ + public Map> getItems() { return items; } + + /** + * @param items the items to set + */ + public void setItems(Map> items) { this.items = items; } + /** * @return a {@code Map} of all themes with their names as keys * @since Envoy v0.2-alpha diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 15e8a83..58bc817 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -1,16 +1,12 @@ package envoy.client.ui; import java.awt.*; -import java.lang.reflect.Constructor; -import java.util.logging.Logger; import javax.swing.JButton; import javax.swing.JPanel; import envoy.client.Settings; -import envoy.client.event.Event; -import envoy.client.event.EventBus; -import envoy.client.util.EnvoyLog; +import envoy.client.SettingsItem; /** * This Component can be used to toggle between two options. e.g. on and @@ -25,23 +21,19 @@ import envoy.client.util.EnvoyLog; */ public class PrimaryToggleSwitch extends JPanel { - private final JButton b = new JButton(""); + private final JButton b = new JButton(); private boolean currentState; - private static final Logger logger = EnvoyLog.getLogger(PrimaryToggleSwitch.class.getSimpleName()); private static final long serialVersionUID = -721155303106833184L; /** * This is the constructor for the PrimaryToggleSwitch. * - * @param initialState The state the toggleSwitch is standardly set to.
- * true: off
- * false: on - * @param eventClass the class of the event dispatched by this toggleSwitch + * @param settingsItem * @since Envoy v0.3-alpha */ - public PrimaryToggleSwitch(boolean initialState, Class> eventClass) { + public PrimaryToggleSwitch(SettingsItem settingsItem) { setEnabled(true); setVisible(true); @@ -63,20 +55,13 @@ public class PrimaryToggleSwitch extends JPanel { setLayout(gbl_toggleSwitch); - setState(initialState); + setState(settingsItem.get()); b.addActionListener((evt) -> { - try { - // Dispatch event - Constructor> constructor = eventClass.getConstructor(boolean.class); - EventBus.getInstance().dispatch(constructor.newInstance(currentState)); - - setState(!currentState); - revalidate(); - repaint(); - } catch (ReflectiveOperationException | SecurityException e) { - logger.warning("An error occured while changing the setting: " + e); - } + settingsItem.set(!currentState); + setState(!currentState); + revalidate(); + repaint(); }); repaint(); @@ -96,7 +81,7 @@ public class PrimaryToggleSwitch extends JPanel { * @param state {@code true} to enable the switch, {@code false} to disable it * @since Envoy 0.3-alpha */ - public void setState(boolean state) { + private void setState(boolean state) { GridBagConstraints gbc_toggleButton = new GridBagConstraints(); if (state) { diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java index 235cee9..3d09993 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -11,7 +11,7 @@ import javax.swing.JOptionPane; import javax.swing.JTextPane; import envoy.client.Settings; -import envoy.client.event.*; +import envoy.client.SettingsItem; import envoy.client.ui.PrimaryToggleSwitch; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; @@ -31,15 +31,7 @@ public class General extends SettingsPanel { private Theme theme; private boolean onCloseState = Settings.getInstance().getCurrentOnCloseMode(); private boolean enterToSend = Settings.getInstance().isEnterToSend(); - - private PrimaryToggleSwitch toggleSwitch; - private JTextPane onCloseModeTextPane = new JTextPane(); - private JTextPane onCloseModeStatePane = new JTextPane(); - - private PrimaryToggleSwitch toggleSwitchEnterToSend; - private JTextPane enterToSendTextPane = new JTextPane(); - private JTextPane enterToSendStatePane = new JTextPane(); - + private static final Logger logger = EnvoyLog.getLogger(General.class.getSimpleName()); private static final long serialVersionUID = -7470848775130754239L; @@ -61,26 +53,16 @@ public class General extends SettingsPanel { gbl_general.rowWeights = new double[] { 0.02, 0.0005, 0.02, 0.0005, 1.0 }; setLayout(gbl_general); - + createSettingElement(0, - OnCloseChangeEvent.class, - Settings.getInstance().getCurrentOnCloseMode(), - toggleSwitch, - onCloseModeStatePane, - onCloseModeTextPane, - "Client runs in the background, when window is closed"); - EventBus.getInstance().register(OnCloseChangeEvent.class, (evt) -> changeOnClose(((OnCloseChangeEvent) evt).get())); + (SettingsItem) Settings.getInstance().getItems().get("onCloseMode")); createSettingElement(2, - EnterToSendEvent.class, - Settings.getInstance().isEnterToSend(), - toggleSwitchEnterToSend, - enterToSendStatePane, - enterToSendTextPane, - "Press Enter to send messages"); - EventBus.getInstance().register(EnterToSendEvent.class, (evt) -> changeEnterToSend(((EnterToSendEvent) evt).get())); + (SettingsItem) Settings.getInstance().getItems().get("enterToSend")); } + // TODO: Move ON / OFF text to PrimaryToggleswitch + /** * This method changes the on close mode of the client. * @@ -91,7 +73,7 @@ public class General extends SettingsPanel { public void changeOnClose(boolean state) { this.onCloseState = state; - onCloseModeStatePane.setText(state ? "ON" : "OFF"); + //onCloseModeStatePane.setText(state ? "ON" : "OFF"); revalidate(); repaint(); } @@ -106,14 +88,16 @@ public class General extends SettingsPanel { public void changeEnterToSend(boolean state) { this.enterToSend = state; - enterToSendStatePane.setText(state ? "ON" : "OFF"); + //enterToSendStatePane.setText(state ? "ON" : "OFF"); revalidate(); repaint(); } - private void createSettingElement(int gridy, Class> eventClass, boolean state, PrimaryToggleSwitch toggleSwitch, - JTextPane stateText, JTextPane descriptionText, String text) { - toggleSwitch = new PrimaryToggleSwitch(state, eventClass); + private void createSettingElement(int gridy, SettingsItem settingsItem) { + JTextPane stateText = new JTextPane(); + JTextPane descriptionText = new JTextPane(); + + PrimaryToggleSwitch toggleSwitch = new PrimaryToggleSwitch(settingsItem); GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); gbc_toggleSwitch.gridx = 1; @@ -121,7 +105,7 @@ public class General extends SettingsPanel { add(toggleSwitch, gbc_toggleSwitch); - stateText.setText(state ? "ON" : "OFF"); + stateText.setText(settingsItem.get() ? "ON" : "OFF"); stateText.setBackground(theme.getCellColor()); stateText.setForeground(theme.getUserNameColor()); stateText.setEditable(false); @@ -133,7 +117,7 @@ public class General extends SettingsPanel { add(stateText, gbc_stateText); - descriptionText.setText(text); + descriptionText.setText(settingsItem.getDescription()); descriptionText.setBackground(theme.getBackgroundColor()); descriptionText.setForeground(theme.getBackgroundColor().invert()); descriptionText.setEditable(false); From 925b993bf5f65f6d3107a5fa3319109565b5e2ef Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Mon, 23 Dec 2019 15:20:20 +0100 Subject: [PATCH 159/474] Removed ON OFF Text --- .../envoy/client/ui/PrimaryToggleSwitch.java | 9 +- .../envoy/client/ui/settings/General.java | 90 +++---------------- 2 files changed, 14 insertions(+), 85 deletions(-) diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 58bc817..7319fe6 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -25,7 +25,7 @@ public class PrimaryToggleSwitch extends JPanel { private boolean currentState; - private static final long serialVersionUID = -721155303106833184L; + private static final long serialVersionUID = -721155303106833184L; /** * This is the constructor for the PrimaryToggleSwitch. @@ -57,12 +57,7 @@ public class PrimaryToggleSwitch extends JPanel { setState(settingsItem.get()); - b.addActionListener((evt) -> { - settingsItem.set(!currentState); - setState(!currentState); - revalidate(); - repaint(); - }); + b.addActionListener((evt) -> { settingsItem.set(!currentState); setState(!currentState); revalidate(); repaint(); }); repaint(); } diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java index 3d09993..e4b5ae3 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -28,10 +28,8 @@ import envoy.client.util.EnvoyLog; */ public class General extends SettingsPanel { - private Theme theme; - private boolean onCloseState = Settings.getInstance().getCurrentOnCloseMode(); - private boolean enterToSend = Settings.getInstance().isEnterToSend(); - + private Theme theme; + private static final Logger logger = EnvoyLog.getLogger(General.class.getSimpleName()); private static final long serialVersionUID = -7470848775130754239L; @@ -48,55 +46,20 @@ public class General extends SettingsPanel { GridBagLayout gbl_general = new GridBagLayout(); gbl_general.columnWidths = new int[] { 1, 1 }; - gbl_general.rowHeights = new int[] { 1, 1, 1, 1, 1 }; + gbl_general.rowHeights = new int[] { 1, 1, 1 }; gbl_general.columnWeights = new double[] { 1.0, 0.1 }; - gbl_general.rowWeights = new double[] { 0.02, 0.0005, 0.02, 0.0005, 1.0 }; + gbl_general.rowWeights = new double[] { 0.02, 0.02, 1.0 }; setLayout(gbl_general); - - createSettingElement(0, - (SettingsItem) Settings.getInstance().getItems().get("onCloseMode")); - createSettingElement(2, - (SettingsItem) Settings.getInstance().getItems().get("enterToSend")); - } + createSettingElement(0, (SettingsItem) Settings.getInstance().getItems().get("onCloseMode")); - // TODO: Move ON / OFF text to PrimaryToggleswitch - - /** - * This method changes the on close mode of the client. - * - * @param state This is the integer that defines weather the toggleSwitch is on - * or off. - * @since Envoy v0.3-alpha - */ - public void changeOnClose(boolean state) { - this.onCloseState = state; - - //onCloseModeStatePane.setText(state ? "ON" : "OFF"); - revalidate(); - repaint(); - } - - /** - * This method changes the enter to send a message setting. - * - * @param state This is the integer that defines weather the toggleSwitch is on - * or off. - * @since Envoy v0.3-alpha - */ - public void changeEnterToSend(boolean state) { - this.enterToSend = state; - - //enterToSendStatePane.setText(state ? "ON" : "OFF"); - revalidate(); - repaint(); + createSettingElement(1, (SettingsItem) Settings.getInstance().getItems().get("enterToSend")); } private void createSettingElement(int gridy, SettingsItem settingsItem) { - JTextPane stateText = new JTextPane(); JTextPane descriptionText = new JTextPane(); - + PrimaryToggleSwitch toggleSwitch = new PrimaryToggleSwitch(settingsItem); GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); @@ -105,49 +68,20 @@ public class General extends SettingsPanel { add(toggleSwitch, gbc_toggleSwitch); - stateText.setText(settingsItem.get() ? "ON" : "OFF"); - stateText.setBackground(theme.getCellColor()); - stateText.setForeground(theme.getUserNameColor()); - stateText.setEditable(false); - - GridBagConstraints gbc_stateText = new GridBagConstraints(); - gbc_stateText.anchor = GridBagConstraints.NORTH; - gbc_stateText.gridx = 1; - gbc_stateText.gridy = gridy + 1; - - add(stateText, gbc_stateText); - descriptionText.setText(settingsItem.getDescription()); descriptionText.setBackground(theme.getBackgroundColor()); descriptionText.setForeground(theme.getBackgroundColor().invert()); descriptionText.setEditable(false); GridBagConstraints gbc_descriptionText = new GridBagConstraints(); - gbc_descriptionText.fill = GridBagConstraints.BOTH; - gbc_descriptionText.gridx = 0; - gbc_descriptionText.gridy = gridy; - gbc_descriptionText.gridheight = 2; - gbc_descriptionText.insets = new Insets(5, 5, 5, 5); + gbc_descriptionText.fill = GridBagConstraints.BOTH; + gbc_descriptionText.gridx = 0; + gbc_descriptionText.gridy = gridy; + gbc_descriptionText.insets = new Insets(5, 5, 5, 5); add(descriptionText, gbc_descriptionText); } @Override - public ActionListener getOkButtonAction() { - return (evt) -> { - if (onCloseState != Settings.getInstance().getCurrentOnCloseMode()) try { - Settings.getInstance().setCurrentOnCloseMode(onCloseState); - JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); - } catch (Exception e) { - logger.log(Level.WARNING, "Close mode could not be changed! ", e); - } - - if (enterToSend != Settings.getInstance().isEnterToSend()) try { - Settings.getInstance().setEnterToSend(enterToSend); - JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); - } catch (Exception e) { - logger.log(Level.WARNING, "Enter to send mode could not be changed! ", e); - } - }; - } + public ActionListener getOkButtonAction() { return null; } } \ No newline at end of file From 5c81a2dfd3e125556252597f5cbcfffab6ca1350 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Dec 2019 15:35:27 +0100 Subject: [PATCH 160/474] Made PrimaryToggleSwitch a sub class of JButton --- .../envoy/client/ui/PrimaryToggleSwitch.java | 68 ++++--------------- .../envoy/client/ui/settings/General.java | 2 - 2 files changed, 14 insertions(+), 56 deletions(-) diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 7319fe6..d6a23cc 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -1,9 +1,9 @@ package envoy.client.ui; -import java.awt.*; +import java.awt.Dimension; +import java.awt.Graphics; import javax.swing.JButton; -import javax.swing.JPanel; import envoy.client.Settings; import envoy.client.SettingsItem; @@ -19,11 +19,9 @@ import envoy.client.SettingsItem; * @author Maximilian Käfer * @since Envoy v0.3-alpha */ -public class PrimaryToggleSwitch extends JPanel { +public class PrimaryToggleSwitch extends JButton { - private final JButton b = new JButton(); - - private boolean currentState; + private boolean state; private static final long serialVersionUID = -721155303106833184L; @@ -34,61 +32,23 @@ public class PrimaryToggleSwitch extends JPanel { * @since Envoy v0.3-alpha */ public PrimaryToggleSwitch(SettingsItem settingsItem) { - setEnabled(true); - setVisible(true); - setPreferredSize(new Dimension(50, 25)); setMinimumSize(new Dimension(50, 25)); setMaximumSize(new Dimension(50, 25)); - b.setPreferredSize(new Dimension(25, 25)); - b.setMinimumSize(new Dimension(25, 25)); - b.setMaximumSize(new Dimension(25, 25)); + setBorderPainted(false); + setFocusPainted(false); + setContentAreaFilled(false); - b.setBackground(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); - - GridBagLayout gbl_toggleSwitch = new GridBagLayout(); - gbl_toggleSwitch.columnWidths = new int[] { 1, 1 }; - gbl_toggleSwitch.rowHeights = new int[] { 1 }; - gbl_toggleSwitch.columnWeights = new double[] { 1.0, 1.0 }; - gbl_toggleSwitch.rowWeights = new double[] { 1.0 }; - - setLayout(gbl_toggleSwitch); - - setState(settingsItem.get()); - - b.addActionListener((evt) -> { settingsItem.set(!currentState); setState(!currentState); revalidate(); repaint(); }); - - repaint(); + addActionListener((evt) -> { state = !state; settingsItem.set(state); revalidate(); repaint(); }); } @Override public void paintComponent(Graphics g) { - g.setColor(Color.LIGHT_GRAY); - g.fillRect(0, 0, 50, 25); - g.setColor(Color.GREEN); - g.fillRect(0, 0, 25, 25); + g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY); + g.fillRect(0, 0, getWidth(), getHeight()); + g.setColor(state ? Color.LIGHT_GRAY + : Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); + g.fillRect(0, getWidth() / 2, getWidth(), getHeight()); } - - /** - * This method sets the state of this {@link PrimaryToggleSwitch}. - * - * @param state {@code true} to enable the switch, {@code false} to disable it - * @since Envoy 0.3-alpha - */ - private void setState(boolean state) { - GridBagConstraints gbc_toggleButton = new GridBagConstraints(); - - if (state) { - gbc_toggleButton.anchor = GridBagConstraints.WEST; - gbc_toggleButton.gridx = 0; - } else { - gbc_toggleButton.anchor = GridBagConstraints.EAST; - gbc_toggleButton.gridx = 1; - } - gbc_toggleButton.gridy = 0; - add(b, gbc_toggleButton); - - currentState = state; - } -} +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java index e4b5ae3..9b6339a 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -4,10 +4,8 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionListener; -import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.JOptionPane; import javax.swing.JTextPane; import envoy.client.Settings; From 9968b708c5a00d27aeedf4d3c69d2954c8d788c4 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Mon, 23 Dec 2019 15:54:55 +0100 Subject: [PATCH 161/474] Fixed weird toggle switch programming from @CyB3rC0nN0R --- .../java/envoy/client/ui/PrimaryToggleSwitch.java | 12 +++++++++--- src/main/java/envoy/client/ui/settings/General.java | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index d6a23cc..6ea198d 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -40,6 +40,7 @@ public class PrimaryToggleSwitch extends JButton { setFocusPainted(false); setContentAreaFilled(false); + state = settingsItem.get(); addActionListener((evt) -> { state = !state; settingsItem.set(state); revalidate(); repaint(); }); } @@ -47,8 +48,13 @@ public class PrimaryToggleSwitch extends JButton { public void paintComponent(Graphics g) { g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY); g.fillRect(0, 0, getWidth(), getHeight()); - g.setColor(state ? Color.LIGHT_GRAY - : Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); - g.fillRect(0, getWidth() / 2, getWidth(), getHeight()); + + g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); + + if (state) { + g.fillRect(25, 0, 25, 25); + } else { + g.fillRect(0, 0, 25, 25); + } } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java index 9b6339a..59a6345 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/General.java @@ -81,5 +81,5 @@ public class General extends SettingsPanel { } @Override - public ActionListener getOkButtonAction() { return null; } + public ActionListener getOkButtonAction() { return (evt) -> {}; } } \ No newline at end of file From a6c4d42c98789eff361763dc41591e5d5521d70c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Dec 2019 16:33:13 +0100 Subject: [PATCH 162/474] Polished settings mechanism * Set initial value of onCloseMode setting to true * Added setting change handlers * Applying settings changes immediately * Made PrimaryToggleSwitch round --- src/main/java/envoy/client/Settings.java | 2 +- src/main/java/envoy/client/SettingsItem.java | 18 ++++++++++--- .../envoy/client/event/EnterToSendEvent.java | 27 ------------------- .../client/event/OnCloseChangeEvent.java | 27 ------------------- .../envoy/client/ui/PrimaryToggleSwitch.java | 11 ++++---- src/main/java/envoy/client/ui/Startup.java | 3 +-- ...General.java => GeneralSettingsPanel.java} | 27 +++++++++++-------- .../client/ui/settings/SettingsScreen.java | 2 +- 8 files changed, 39 insertions(+), 78 deletions(-) delete mode 100644 src/main/java/envoy/client/event/EnterToSendEvent.java delete mode 100644 src/main/java/envoy/client/event/OnCloseChangeEvent.java rename src/main/java/envoy/client/ui/settings/{General.java => GeneralSettingsPanel.java} (67%) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 9732248..199653d 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -102,7 +102,7 @@ public class Settings { private void supplementDefaults() { items.putIfAbsent("enterToSend", new SettingsItem<>(true, "Enter to send", "Sends a message by pressing the enter key.")); - items.putIfAbsent("onCloseMode", new SettingsItem<>(false, "Hide on close", "Hides the chat window when it is closed.")); + items.putIfAbsent("onCloseMode", new SettingsItem<>(true, "Hide on close", "Hides the chat window when it is closed.")); items.putIfAbsent("currentTheme", new SettingsItem<>("dark", null)); } diff --git a/src/main/java/envoy/client/SettingsItem.java b/src/main/java/envoy/client/SettingsItem.java index 23da76a..4c26201 100644 --- a/src/main/java/envoy/client/SettingsItem.java +++ b/src/main/java/envoy/client/SettingsItem.java @@ -3,6 +3,7 @@ package envoy.client; import java.io.Serializable; import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; import javax.swing.JComponent; @@ -21,12 +22,14 @@ public class SettingsItem implements Serializable { private Class componentClass; private String userFriendlyName, description; + transient private Consumer changeHandler; + private static final Map, Class> componentClasses = new HashMap<>(); - + private static final long serialVersionUID = 2146837835556852218L; static { - componentClasses.put(boolean.class, PrimaryToggleSwitch.class); + componentClasses.put(Boolean.class, PrimaryToggleSwitch.class); } public SettingsItem(T value, String userFriendlyName, String description) { @@ -53,7 +56,11 @@ public class SettingsItem implements Serializable { /** * @param value the value to set */ - public void set(T value) { this.value = value; } + public void set(T value) { + if(changeHandler != null && value != this.value) + changeHandler.accept(value); + this.value = value; + } /** * @return the componentClass @@ -84,4 +91,9 @@ public class SettingsItem implements Serializable { * @param description the description to set */ public void setDescription(String description) { this.description = description; } + + /** + * @param changeHandler the changeHandler to set + */ + public void setChangeHandler(Consumer changeHandler) { this.changeHandler = changeHandler; changeHandler.accept(value); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/event/EnterToSendEvent.java b/src/main/java/envoy/client/event/EnterToSendEvent.java deleted file mode 100644 index 7b26e0a..0000000 --- a/src/main/java/envoy/client/event/EnterToSendEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package envoy.client.event; - -/** - * Encapsulates a change to the {@code enterToSend} setting.
- *
- * Project: envoy-client
- * File: EnterToSendEvent.java
- * Created: 22 Dec 2019
- * - * @author Maximilian Käfer - * @since Envoy v0.3-alpha - */ -public class EnterToSendEvent implements Event { - - private boolean mode; - - /** - * Initializes an {@link EnterToSendEvent}. - * - * @param mode the state of the {@code enterToSend} setting - * @since Envoy 0.3-alpha - */ - public EnterToSendEvent(boolean mode) { this.mode = mode; } - - @Override - public Boolean get() { return mode; } -} \ No newline at end of file diff --git a/src/main/java/envoy/client/event/OnCloseChangeEvent.java b/src/main/java/envoy/client/event/OnCloseChangeEvent.java deleted file mode 100644 index 2d86fb6..0000000 --- a/src/main/java/envoy/client/event/OnCloseChangeEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package envoy.client.event; - -/** - * Encapsulates a change to the {@code currentOnCloseMode} setting.
- *
- * Project: envoy-client
- * File: OnCloseChangeEvent.java
- * Created: 22 Dec 2019
- * - * @author Maximilian Käfer - * @since Envoy v0.3-alpha - */ -public class OnCloseChangeEvent implements Event { - - private boolean closeMode; - - /** - * Initializes an {@link OnCloseChangeEvent}. - * - * @param closeMode the state of the {@code currentOnCloseMode} setting - * @since Envoy 0.3-alpha - */ - public OnCloseChangeEvent(boolean closeMode) { this.closeMode = closeMode; } - - @Override - public Boolean get() { return closeMode; } -} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 6ea198d..8e91ab5 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -47,14 +47,13 @@ public class PrimaryToggleSwitch extends JButton { @Override public void paintComponent(Graphics g) { g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY); - g.fillRect(0, 0, getWidth(), getHeight()); + g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25); g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); - if (state) { - g.fillRect(25, 0, 25, 25); - } else { - g.fillRect(0, 0, 25, 25); - } + if (state) + g.fillRoundRect(25, 0, 25, 25, 25, 25); + else + g.fillRoundRect(0, 0, 25, 25, 25, 25); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 5e5bc92..8e57a08 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -143,8 +143,7 @@ public class Startup { new StatusTrayIcon(chatWindow).show(); // If the tray icon is supported and corresponding settings is set, hide the chat window on close - if (Settings.getInstance().getCurrentOnCloseMode()) - chatWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + Settings.getInstance().getItems().get("onCloseMode").setChangeHandler((onCloseMode) -> chatWindow.setDefaultCloseOperation((boolean) onCloseMode ? JFrame.HIDE_ON_CLOSE : JFrame.EXIT_ON_CLOSE)); } catch (EnvoyException e) { logger.warning("The StatusTrayIcon is not supported on this platform!"); } diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java similarity index 67% rename from src/main/java/envoy/client/ui/settings/General.java rename to src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index 59a6345..60e5458 100644 --- a/src/main/java/envoy/client/ui/settings/General.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -4,13 +4,14 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionListener; +import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.JComponent; import javax.swing.JTextPane; import envoy.client.Settings; import envoy.client.SettingsItem; -import envoy.client.ui.PrimaryToggleSwitch; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; @@ -24,12 +25,13 @@ import envoy.client.util.EnvoyLog; * @author Maximilian Käfer * @since Envoy v0.3-alpha */ -public class General extends SettingsPanel { +public class GeneralSettingsPanel extends SettingsPanel { private Theme theme; - private static final Logger logger = EnvoyLog.getLogger(General.class.getSimpleName()); - private static final long serialVersionUID = -7470848775130754239L; + private static final String[] items = { "onCloseMode", "enterToSend" }; + private static final Logger logger = EnvoyLog.getLogger(GeneralSettingsPanel.class.getSimpleName()); + private static final long serialVersionUID = -7470848775130754239L; /** * This is the constructor for the General class. Here the user can set general @@ -37,7 +39,7 @@ public class General extends SettingsPanel { * * @since Envoy 0.3-alpha */ - public General() { + public GeneralSettingsPanel() { theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); setBackground(theme.getCellColor()); @@ -50,21 +52,24 @@ public class General extends SettingsPanel { setLayout(gbl_general); - createSettingElement(0, (SettingsItem) Settings.getInstance().getItems().get("onCloseMode")); - - createSettingElement(1, (SettingsItem) Settings.getInstance().getItems().get("enterToSend")); + for (int i = 0; i < items.length; i++) + try { + createSettingElement(i, Settings.getInstance().getItems().get(items[i])); + } catch (SecurityException | ReflectiveOperationException e) { + logger.log(Level.WARNING, "Could not create settings item", e); + } } - private void createSettingElement(int gridy, SettingsItem settingsItem) { + private void createSettingElement(int gridy, SettingsItem settingsItem) throws SecurityException, ReflectiveOperationException { JTextPane descriptionText = new JTextPane(); - PrimaryToggleSwitch toggleSwitch = new PrimaryToggleSwitch(settingsItem); + JComponent settingComponent = settingsItem.getComponent(); GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); gbc_toggleSwitch.gridx = 1; gbc_toggleSwitch.gridy = gridy; - add(toggleSwitch, gbc_toggleSwitch); + add(settingComponent, gbc_toggleSwitch); descriptionText.setText(settingsItem.getDescription()); descriptionText.setBackground(theme.getBackgroundColor()); diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index b971625..b37bf9a 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -57,7 +57,7 @@ public class SettingsScreen extends JDialog { public SettingsScreen() { // Initialize settings pages Map> panels = new HashMap<>(); - panels.put("General", General.class); + panels.put("General", GeneralSettingsPanel.class); panels.put("Color Themes", ThemeCustomizationPanel.class); setBounds(10, 10, 450, 650); From 5c7563a06b92b0503226881ce3f713b69e56f143 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Mon, 23 Dec 2019 16:43:59 +0100 Subject: [PATCH 163/474] Javadoc and short notation --- src/main/java/envoy/client/ui/PrimaryToggleSwitch.java | 7 ++----- .../envoy/client/ui/settings/GeneralSettingsPanel.java | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 8e91ab5..591f060 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -17,6 +17,7 @@ import envoy.client.SettingsItem; * Created: 21 Dec 2019
* * @author Maximilian Käfer + * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ public class PrimaryToggleSwitch extends JButton { @@ -50,10 +51,6 @@ public class PrimaryToggleSwitch extends JButton { g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25); g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); - - if (state) - g.fillRoundRect(25, 0, 25, 25, 25, 25); - else - g.fillRoundRect(0, 0, 25, 25, 25, 25); + g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index 60e5458..ee8f619 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -19,7 +19,7 @@ import envoy.client.util.EnvoyLog; * Displays GUI components that allow general settings regarding the client.
*
* Project: envoy-client
- * File: General.java
+ * File: GeneralSettingsPanel.java
* Created: 21 Dec 2019
* * @author Maximilian Käfer From f6d6ef0a3a79ae94f7d8c5bc75e72baa292058ed Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Dec 2019 16:59:57 +0100 Subject: [PATCH 164/474] Added Javadoc for SettingsItem and SerializationUtils. --- src/main/java/envoy/client/SettingsItem.java | 54 +++++++++++++++++-- .../envoy/client/ui/PrimaryToggleSwitch.java | 9 ++-- .../envoy/client/util/SerializationUtils.java | 21 +++++++- 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/src/main/java/envoy/client/SettingsItem.java b/src/main/java/envoy/client/SettingsItem.java index 4c26201..287b6e9 100644 --- a/src/main/java/envoy/client/SettingsItem.java +++ b/src/main/java/envoy/client/SettingsItem.java @@ -10,11 +10,16 @@ import javax.swing.JComponent; import envoy.client.ui.PrimaryToggleSwitch; /** + * Encapsulates a persistent value that is directly or indirectly mutable by the + * user.
+ *
* Project: envoy-clientChess
* File: SettingsItem.java
* Created: 23.12.2019
* + * @param the type of this {@link SettingsItem}'s value * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha */ public class SettingsItem implements Serializable { @@ -32,17 +37,42 @@ public class SettingsItem implements Serializable { componentClasses.put(Boolean.class, PrimaryToggleSwitch.class); } + /** + * Initializes a {@link SettingsItem}. The default value's class will be mapped + * to a {@link JComponent} that can be used to display this {@link SettingsItem} + * to the user. + * + * @param value the default value + * @param userFriendlyName the user friendly name (short) + * @param description the description (long) + * @since Envoy v0.3-alpha + */ public SettingsItem(T value, String userFriendlyName, String description) { this(value, componentClasses.get(value.getClass())); this.userFriendlyName = userFriendlyName; this.description = description; } + /** + * Initializes a {@link SettingsItem}. The default value's class will be mapped + * to a specific {@link JComponent}. The mapping can also be disables if this + * parameter is {@code null}. In that case a {@link NullPointerException} will + * be thrown if the method {@link SettingsItem#getComponent()} is called. + * + * @param value the default value + * @param componentClass the class of the {@link JComponent} to represent this {@link SettingsItem} with + * @since Envoy v0.3-alpha + */ public SettingsItem(T value, Class componentClass) { this.value = value; this.componentClass = componentClass; } + /** + * @return an instance of the {@link JComponent} that represents this {@link SettingsItem} + * @throws ReflectiveOperationException if the component initialization failed + * @throws SecurityException if the component initialization failed + */ public JComponent getComponent() throws ReflectiveOperationException, SecurityException { if (componentClass == null) throw new NullPointerException("Component class is null"); return componentClass.getConstructor(SettingsItem.class).newInstance(this); @@ -50,50 +80,68 @@ public class SettingsItem implements Serializable { /** * @return the value + * @since Envoy v0.3-alpha */ public T get() { return value; } /** + * Changes the value of this {@link SettingsItem}. If a {@code ChangeHandler} if + * defined, it will be invoked with this value. + * * @param value the value to set + * @since Envoy v0.3-alpha */ public void set(T value) { - if(changeHandler != null && value != this.value) - changeHandler.accept(value); + if (changeHandler != null && value != this.value) changeHandler.accept(value); this.value = value; } /** * @return the componentClass + * @since Envoy v0.3-alpha */ public Class getComponentClass() { return componentClass; } /** * @param componentClass the componentClass to set + * @since Envoy v0.3-alpha */ public void setComponentClass(Class componentClass) { this.componentClass = componentClass; } /** * @return the userFriendlyName + * @since Envoy v0.3-alpha */ public String getUserFriendlyName() { return userFriendlyName; } /** * @param userFriendlyName the userFriendlyName to set + * @since Envoy v0.3-alpha */ public void setUserFriendlyName(String userFriendlyName) { this.userFriendlyName = userFriendlyName; } /** * @return the description + * @since Envoy v0.3-alpha */ public String getDescription() { return description; } /** * @param description the description to set + * @since Envoy v0.3-alpha */ public void setDescription(String description) { this.description = description; } /** + * Sets a {@code ChangeHandler} for this {@link SettingsItem}. It will be + * invoked with the current value once during the registration and every time + * when the value changes. + * * @param changeHandler the changeHandler to set + * @since Envoy v0.3-alpha */ - public void setChangeHandler(Consumer changeHandler) { this.changeHandler = changeHandler; changeHandler.accept(value); } + public void setChangeHandler(Consumer changeHandler) { + this.changeHandler = changeHandler; + changeHandler.accept(value); + } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 591f060..2882a05 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -9,8 +9,8 @@ import envoy.client.Settings; import envoy.client.SettingsItem; /** - * This Component can be used to toggle between two options. e.g. on and - * off.
+ * This component can be used to toggle between two options. This will change + * the state of a {@code boolean} {@link SettingsItem}.
*
* Project: envoy-client
* File: PrimaryToggleSwitch.java
@@ -27,9 +27,10 @@ public class PrimaryToggleSwitch extends JButton { private static final long serialVersionUID = -721155303106833184L; /** - * This is the constructor for the PrimaryToggleSwitch. + * Initializes a {@link PrimaryToggleSwitch}. * - * @param settingsItem + * @param settingsItem the {@link SettingsItem} that is controlled by this + * {@link PrimaryToggleSwitch} * @since Envoy v0.3-alpha */ public PrimaryToggleSwitch(SettingsItem settingsItem) { diff --git a/src/main/java/envoy/client/util/SerializationUtils.java b/src/main/java/envoy/client/util/SerializationUtils.java index 5a4b842..f0cc70f 100644 --- a/src/main/java/envoy/client/util/SerializationUtils.java +++ b/src/main/java/envoy/client/util/SerializationUtils.java @@ -10,11 +10,22 @@ import envoy.exception.EnvoyException; * Created: 23.12.2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha */ public class SerializationUtils { private SerializationUtils() {} + /** + * Deserializes an arbitrary {@link Serializable} object from a file. + * + * @param the type of the object to deserialize + * @param file the file deserialize from + * @param serializedClass the class of the object to deserialize + * @return the deserialized object + * @throws EnvoyException if an error occurred during deserialization + * @since Envoy v0.3-alpha + */ public static T read(File file, Class serializedClass) throws EnvoyException { if (file == null) throw new NullPointerException("File is null"); try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { @@ -24,6 +35,14 @@ public class SerializationUtils { } } + /** + * Serializes an arbitrary object to a file. + * + * @param file the file to serialize to + * @param obj the object to serialize + * @throws IOException if an error occurred during serialization + * @since Envoy v0.3-alpha + */ public static void write(File file, Object obj) throws IOException { if (file == null) throw new NullPointerException("File is null"); if (obj == null) throw new NullPointerException("Object to serialize is null"); @@ -35,4 +54,4 @@ public class SerializationUtils { out.writeObject(obj); } } -} +} \ No newline at end of file From 91f780d1c6e86a8a9f0242e10a7fa65a7cfa380b Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Mon, 23 Dec 2019 19:00:17 +0100 Subject: [PATCH 165/474] Fixed theme customization bug --- .../java/envoy/client/ui/settings/ThemeCustomizationPanel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 8c3f9f4..c07bc56 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -194,7 +194,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { button.addActionListener((evt) -> { try { - Color newColor = (Color) JColorChooser.showDialog(null, "Choose a color", color); + java.awt.Color c = JColorChooser.showDialog(null, "Choose a color", color); + Color newColor = new Color(c.getRGB()); if (newColor.getRGB() != color.getRGB()) { logger.log(Level.FINEST, "New Color: " + String.valueOf(color.getRGB())); // TODO: When Theme changed in same settings screen, color variable doesn't From f8cce7ed06bd3641265f959eefac8d1d57e0c07f Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Dec 2019 19:37:09 +0100 Subject: [PATCH 166/474] Added Javadoc since tag to SettingsItem --- src/main/java/envoy/client/SettingsItem.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/SettingsItem.java b/src/main/java/envoy/client/SettingsItem.java index 287b6e9..4de2a47 100644 --- a/src/main/java/envoy/client/SettingsItem.java +++ b/src/main/java/envoy/client/SettingsItem.java @@ -72,6 +72,7 @@ public class SettingsItem implements Serializable { * @return an instance of the {@link JComponent} that represents this {@link SettingsItem} * @throws ReflectiveOperationException if the component initialization failed * @throws SecurityException if the component initialization failed + * @since Envoy v0.3-alpha */ public JComponent getComponent() throws ReflectiveOperationException, SecurityException { if (componentClass == null) throw new NullPointerException("Component class is null"); @@ -144,4 +145,4 @@ public class SettingsItem implements Serializable { this.changeHandler = changeHandler; changeHandler.accept(value); } -} \ No newline at end of file +} From d2ee659ea75f53ed6b8471e861bc0b7063fc6299 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Wed, 25 Dec 2019 21:43:59 +0100 Subject: [PATCH 167/474] Fixed possible name conflict when creating new themes. --- .../ui/settings/ThemeCustomizationPanel.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index c07bc56..19cceb0 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -5,6 +5,7 @@ import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Arrays; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -118,7 +119,10 @@ public class ThemeCustomizationPanel extends SettingsPanel { return (evt) -> { if (themeChanged) { try { - String name = JOptionPane.showInputDialog("Enter a name for the new theme"); + String name = ""; + while (name == "") { + name = newName(); + } logger.log(Level.FINEST, name); Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); @@ -229,4 +233,16 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.add(button, gbc_button); } + + private String newName () { + String name = JOptionPane.showInputDialog("Enter a name for the new theme"); + for (Map.Entry entry : Settings.getInstance().getThemes().entrySet()) { + System.out.println(entry.getKey().toString()); + if(entry.getKey().equalsIgnoreCase(name)) { + JOptionPane.showMessageDialog(getParent(), "Name is already used! Please choose another one."); + return ""; + } + } + return name; + } } \ No newline at end of file From c732c0cf451836eb2c93f327b060b9e4b73eb825 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Thu, 26 Dec 2019 21:46:35 +0100 Subject: [PATCH 168/474] Added new theme name choose window * Added NewThemeScreen Class OptionsScreen when name conflict * Added functionality to overwrite themes. --- .../client/ui/settings/NewThemeScreen.java | 260 ++++++++++++++++++ .../client/ui/settings/SettingsScreen.java | 3 +- .../ui/settings/ThemeCustomizationPanel.java | 84 +++--- 3 files changed, 309 insertions(+), 38 deletions(-) create mode 100644 src/main/java/envoy/client/ui/settings/NewThemeScreen.java diff --git a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java new file mode 100644 index 0000000..48df3b0 --- /dev/null +++ b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java @@ -0,0 +1,260 @@ +package envoy.client.ui.settings; + +import java.awt.*; +import java.util.logging.Logger; + +import javax.swing.*; + +import envoy.client.Settings; +import envoy.client.ui.PrimaryButton; +import envoy.client.ui.PrimaryTextArea; +import envoy.client.ui.Theme; +import envoy.client.util.EnvoyLog; + +/** + * Displays window where you can choose a name for the new {@link Theme}. + *
+ * Project: envoy-client
+ * File: NewThemeScreen.java
+ * Created: 26 Dec 2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.3-alpha + */ +public class NewThemeScreen extends JDialog { + + private final JPanel standardPanel = new JPanel(); + private final JPanel secondaryPanel = new JPanel(); + private JTextPane text = new JTextPane(); + private PrimaryTextArea nameEnterTextArea = new PrimaryTextArea(4); + private PrimaryButton confirmButton = new PrimaryButton("Confirm"); + + private JTextPane errorText = new JTextPane(); + private PrimaryButton otherName = new PrimaryButton("Other Name"); + private PrimaryButton overwrite = new PrimaryButton("Overwrite"); + + private static final Logger logger = EnvoyLog.getLogger(NewThemeScreen.class.getSimpleName()); + private static final long serialVersionUID = 2369985550946300976L; + + /** + * Creates a window, where you can choose a name for a new {@link Theme}.
+ * There are two versions of this Window. The first one is responsible for + * choosing the name, the second one appears, the the name already exists. + * + * @param parentClass The class, where this constructor is invoked. + * @since Envoy v0.3-alpha + */ + public NewThemeScreen(ThemeCustomizationPanel parentClass) { + setTitle("New Theme"); + setDimensions(true, parentClass); + setVisible(true); + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + setModal(true); + // TODO: check modalitly + // setModalityType(DEFAULT_MODALITY_TYPE); + + Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + + getContentPane().setLayout(new BorderLayout()); + { + standardPanel.setBackground(theme.getBackgroundColor()); + secondaryPanel.setBackground(theme.getBackgroundColor()); + loadStandardContent(theme, parentClass); + } + } + + private void setDimensions(boolean isStandard, ThemeCustomizationPanel parentClass) { + if (isStandard == true) { + setPreferredSize(new Dimension(300, 170)); + setMinimumSize(new Dimension(300, 170)); + setMaximumSize(new Dimension(300, 170)); + setBounds(parentClass.getLocation().x + (parentClass.getSize().width), + parentClass.getLocation().y + (parentClass.getSize().height / 2), + 300, + 170); + } else { + setPreferredSize(new Dimension(300, 225)); + setMinimumSize(new Dimension(300, 225)); + setMaximumSize(new Dimension(300, 225)); + setBounds(parentClass.getLocation().x + (parentClass.getSize().width), + parentClass.getLocation().y + (parentClass.getSize().height / 2), + 300, + 225); + } + } + + private void loadStandardContent(Theme theme, ThemeCustomizationPanel parentClass) { + getContentPane().removeAll(); + + // ContentPane + GridBagLayout gbl_contentPanel = new GridBagLayout(); + + gbl_contentPanel.columnWidths = new int[] { 1, 1 }; + gbl_contentPanel.rowHeights = new int[] { 1, 1, 1 }; + gbl_contentPanel.columnWeights = new double[] { 1, 1 }; + gbl_contentPanel.rowWeights = new double[] { 1, 1, 1 }; + + getContentPane().add(standardPanel, BorderLayout.CENTER); + standardPanel.setLayout(gbl_contentPanel); + + // text.setFont(new Font()); + text.setText("Please enter a name for the new Theme"); + text.setAlignmentX(CENTER_ALIGNMENT); + text.setBackground(theme.getCellColor()); + text.setForeground(theme.getUserNameColor()); + text.setEditable(false); + + GridBagConstraints gbc_text = new GridBagConstraints(); + gbc_text.fill = GridBagConstraints.HORIZONTAL; + gbc_text.gridx = 0; + gbc_text.gridy = 0; + gbc_text.gridwidth = 2; + gbc_text.insets = new Insets(5, 5, 5, 5); + + standardPanel.add(text, gbc_text); + + nameEnterTextArea.setBackground(theme.getCellColor()); + nameEnterTextArea.setForeground(theme.getTypingMessageColor()); + nameEnterTextArea.setText(""); + nameEnterTextArea.setEditable(true); + + GridBagConstraints gbc_input = new GridBagConstraints(); + gbc_input.fill = GridBagConstraints.HORIZONTAL; + gbc_input.gridx = 0; + gbc_input.gridy = 1; + gbc_input.gridwidth = 2; + gbc_input.insets = new Insets(5, 5, 5, 5); + + standardPanel.add(nameEnterTextArea, gbc_input); + + confirmButton.setBackground(theme.getInteractableBackgroundColor()); + confirmButton.setForeground(theme.getInteractableForegroundColor()); + + GridBagConstraints gbc_confirmButton = new GridBagConstraints(); + gbc_confirmButton.gridx = 0; + gbc_confirmButton.gridy = 2; + gbc_confirmButton.gridwidth = 2; + gbc_confirmButton.insets = new Insets(5, 5, 5, 5); + + standardPanel.add(confirmButton, gbc_confirmButton); + + confirmButton.addActionListener((evt) -> { + if (!nameEnterTextArea.getText().isEmpty()) try { + if (Settings.getInstance().getThemes().containsKey(nameEnterTextArea.getText())) { + // load other panel + setDimensions(false, parentClass); + loadSecondaryPage(theme, parentClass); + } else { + parentClass.newTheme(nameEnterTextArea.getText()); + dispose(); + } + } catch (Exception e) { + logger.info("" + "Name could not be set! " + e); + e.printStackTrace(); + } + }); + } + + private void loadSecondaryPage(Theme theme, ThemeCustomizationPanel parentClass) { + // ContentPane + getContentPane().removeAll(); + + GridBagLayout gbl_secondaryPanel = new GridBagLayout(); + + gbl_secondaryPanel.columnWidths = new int[] { 1, 1 }; + gbl_secondaryPanel.rowHeights = new int[] { 1, 1, 1, 1 }; + gbl_secondaryPanel.columnWeights = new double[] { 1, 1 }; + gbl_secondaryPanel.rowWeights = new double[] { 1, 1, 1, 1 }; + + getContentPane().add(secondaryPanel, BorderLayout.CENTER); + secondaryPanel.setLayout(gbl_secondaryPanel); + + // text.setFont(new Font()); + text.setText("Please enter a name for the new Theme"); + text.setAlignmentX(CENTER_ALIGNMENT); + text.setBackground(theme.getCellColor()); + text.setForeground(theme.getUserNameColor()); + text.setEditable(false); + + GridBagConstraints gbc_text = new GridBagConstraints(); + gbc_text.fill = GridBagConstraints.HORIZONTAL; + gbc_text.gridx = 0; + gbc_text.gridy = 0; + gbc_text.gridwidth = 2; + gbc_text.insets = new Insets(5, 5, 5, 5); + + secondaryPanel.add(text, gbc_text); + + nameEnterTextArea.setBackground(theme.getCellColor()); + nameEnterTextArea.setForeground(theme.getTypingMessageColor()); + nameEnterTextArea.setEditable(false); + + GridBagConstraints gbc_input = new GridBagConstraints(); + gbc_input.fill = GridBagConstraints.HORIZONTAL; + gbc_input.gridx = 0; + gbc_input.gridy = 1; + gbc_input.gridwidth = 2; + gbc_input.insets = new Insets(5, 5, 5, 5); + + secondaryPanel.add(nameEnterTextArea, gbc_input); + + errorText.setText("The name does already exist. Choose another one or overwrite the old theme."); + errorText.setAlignmentX(CENTER_ALIGNMENT); + errorText.setBackground(theme.getCellColor()); + errorText.setForeground(theme.getUserNameColor()); + errorText.setEditable(false); + + GridBagConstraints gbc_errorText = new GridBagConstraints(); + gbc_errorText.fill = GridBagConstraints.HORIZONTAL; + gbc_errorText.gridx = 0; + gbc_errorText.gridy = 2; + gbc_errorText.gridwidth = 2; + gbc_errorText.insets = new Insets(5, 5, 5, 5); + + secondaryPanel.add(errorText, gbc_errorText); + + otherName.setBackground(theme.getInteractableBackgroundColor()); + otherName.setForeground(theme.getInteractableForegroundColor()); + + GridBagConstraints gbc_otherName = new GridBagConstraints(); + gbc_otherName.gridx = 0; + gbc_otherName.gridy = 3; + gbc_otherName.insets = new Insets(5, 5, 5, 5); + + secondaryPanel.add(otherName, gbc_otherName); + + overwrite.setBackground(theme.getInteractableBackgroundColor()); + overwrite.setForeground(theme.getInteractableForegroundColor()); + + GridBagConstraints gbc_overwrite = new GridBagConstraints(); + gbc_overwrite.gridx = 1; + gbc_overwrite.gridy = 3; + gbc_overwrite.insets = new Insets(5, 5, 5, 5); + + secondaryPanel.add(overwrite, gbc_overwrite); + + otherName.addActionListener((evt) -> { + try { + setDimensions(true, parentClass); + loadStandardContent(theme, parentClass); + + } catch (Exception e) { + logger.info("Window could not be updated! " + e); + e.printStackTrace(); + } + + }); + + overwrite.addActionListener((evt) -> { + try { + dispose(); + parentClass.overwriteTheme(nameEnterTextArea.getText()); + + } catch (Exception e) { + logger.info("Error while overwriting the theme! " + e); + e.printStackTrace(); + } + + }); + } +} diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index b37bf9a..022f87f 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -162,7 +162,8 @@ public class SettingsScreen extends JDialog { EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme(((ThemeChangeEvent) evt).get())); setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - setModal(true); + //setModal(true); + //TODO: check modalitly } private void applyTheme(Theme theme) { diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 19cceb0..08d2357 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -5,7 +5,6 @@ import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Arrays; -import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -119,36 +118,15 @@ public class ThemeCustomizationPanel extends SettingsPanel { return (evt) -> { if (themeChanged) { try { - String name = ""; - while (name == "") { - name = newName(); - } - logger.log(Level.FINEST, name); - Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); - themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); - themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(name).getThemeName(); - - temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); - - themes.addItem(themeArray[themeArray.length - 1]); - themes.setSelectedIndex(themeArray.length - 1); - + new NewThemeScreen(this).setVisible(true); } catch (Exception e) { logger.info("New theme couldn't be created! " + e); e.printStackTrace(); } themeChanged = false; + } else { + updateCurrentTheme(); } - - Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); - logger.log(Level.FINER, "Setting theme: " + selectedTheme.getThemeName()); - - final Theme currentTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - updateColorVariables(currentTheme); - EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); - - revalidate(); - repaint(); }; } @@ -198,8 +176,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { button.addActionListener((evt) -> { try { - java.awt.Color c = JColorChooser.showDialog(null, "Choose a color", color); - Color newColor = new Color(c.getRGB()); + java.awt.Color c = JColorChooser.showDialog(null, "Choose a color", color); + Color newColor = new Color(c.getRGB()); if (newColor.getRGB() != color.getRGB()) { logger.log(Level.FINEST, "New Color: " + String.valueOf(color.getRGB())); // TODO: When Theme changed in same settings screen, color variable doesn't @@ -233,16 +211,48 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.add(button, gbc_button); } + + private void updateCurrentTheme() { + Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); + logger.log(Level.FINER, "Setting theme: " + selectedTheme.getThemeName()); + + final Theme currentTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + applyTheme(currentTheme); + updateColorVariables(currentTheme); + EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); + temporaryTheme = new Theme("temporaryTheme", currentTheme); + + revalidate(); + repaint(); + } - private String newName () { - String name = JOptionPane.showInputDialog("Enter a name for the new theme"); - for (Map.Entry entry : Settings.getInstance().getThemes().entrySet()) { - System.out.println(entry.getKey().toString()); - if(entry.getKey().equalsIgnoreCase(name)) { - JOptionPane.showMessageDialog(getParent(), "Name is already used! Please choose another one."); - return ""; - } - } - return name; + /** + * Adds a new {@link Theme} to the theme map. + * + * @param name The name of the new {@link Theme}. + * @since Envoy v0.3-alpha + */ + public void newTheme(String name) { + logger.log(Level.FINEST, name); + Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); + themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); + themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(name).getThemeName(); + + themes.addItem(themeArray[themeArray.length - 1]); + themes.setSelectedIndex(themeArray.length - 1); + + updateCurrentTheme(); + } + + /** + * Overwrites a specific {@link Theme} located in the theme map and sets the selected {@link Theme} to this new {@link Theme}. + * + * @param key The name of the {@link Theme} to be overwritten. + * @since Envoy v0.3-alpha + */ + public void overwriteTheme(String key) { + Settings.getInstance().getThemes().replace(key, new Theme(key, temporaryTheme)); + selectedTheme = Settings.getInstance().getThemes().get(key); + updateCurrentTheme(); } } \ No newline at end of file From aad7fadc507a75cf53c8f126d346bc3d07229cee Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Fri, 27 Dec 2019 13:30:40 +0100 Subject: [PATCH 169/474] Fixed Javadoc comment --- src/main/java/envoy/client/ui/settings/NewThemeScreen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java index 48df3b0..3fb2db0 100644 --- a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java +++ b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java @@ -39,7 +39,7 @@ public class NewThemeScreen extends JDialog { /** * Creates a window, where you can choose a name for a new {@link Theme}.
* There are two versions of this Window. The first one is responsible for - * choosing the name, the second one appears, the the name already exists. + * choosing the name, the second one appears, if the name already exists. * * @param parentClass The class, where this constructor is invoked. * @since Envoy v0.3-alpha From f0a96b8e394f170ed5ca64396d8942e09647ca5b Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Fri, 27 Dec 2019 16:56:48 +0200 Subject: [PATCH 170/474] Added instantaneous theme change, fixed dialog modality --- src/main/java/envoy/client/Settings.java | 7 + src/main/java/envoy/client/ui/Color.java | 2 + .../ui/settings/GeneralSettingsPanel.java | 5 +- .../client/ui/settings/NewThemeScreen.java | 110 +++++--------- .../client/ui/settings/SettingsPanel.java | 10 ++ .../client/ui/settings/SettingsScreen.java | 5 +- .../ui/settings/ThemeCustomizationPanel.java | 141 +++++++----------- 7 files changed, 120 insertions(+), 160 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 199653d..cdecc33 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -186,4 +186,11 @@ public class Settings { * @since Envoy v0.2-alpha */ public void setThemes(Map themes) { this.themes = themes; } + + /** + * @param themeName the name of the {@link Theme} to get + * @return the {@link Theme} with the specified name + * @since Envoy v0.3-alpha + */ + public Theme getTheme(String themeName) { return themes.get(themeName); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Color.java b/src/main/java/envoy/client/ui/Color.java index 33be64b..18d6ca6 100644 --- a/src/main/java/envoy/client/ui/Color.java +++ b/src/main/java/envoy/client/ui/Color.java @@ -79,6 +79,8 @@ public class Color extends java.awt.Color { private static final long serialVersionUID = -9166233199998257344L; + public Color(java.awt.Color other) { this(other.getRGB()); } + public Color(int rgb) { super(rgb); } public Color(int rgba, boolean hasalpha) { super(rgba, hasalpha); } diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index ee8f619..d76d558 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -37,9 +37,12 @@ public class GeneralSettingsPanel extends SettingsPanel { * This is the constructor for the General class. Here the user can set general * settings for the client. * + * @param parent the {@link SettingsScreen} as a part of which this + * {@link SettingsPanel} is displayed * @since Envoy 0.3-alpha */ - public GeneralSettingsPanel() { + public GeneralSettingsPanel(SettingsScreen parent) { + super(parent); theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); setBackground(theme.getCellColor()); diff --git a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java index 48df3b0..e3c9301 100644 --- a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java +++ b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java @@ -1,15 +1,16 @@ package envoy.client.ui.settings; import java.awt.*; -import java.util.logging.Logger; +import java.util.function.Consumer; -import javax.swing.*; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JTextPane; import envoy.client.Settings; import envoy.client.ui.PrimaryButton; import envoy.client.ui.PrimaryTextArea; import envoy.client.ui.Theme; -import envoy.client.util.EnvoyLog; /** * Displays window where you can choose a name for the new {@link Theme}. @@ -33,57 +34,47 @@ public class NewThemeScreen extends JDialog { private PrimaryButton otherName = new PrimaryButton("Other Name"); private PrimaryButton overwrite = new PrimaryButton("Overwrite"); - private static final Logger logger = EnvoyLog.getLogger(NewThemeScreen.class.getSimpleName()); - private static final long serialVersionUID = 2369985550946300976L; + private final Consumer newThemeAction, modifyThemeAction; + + private static final long serialVersionUID = 2369985550946300976L; /** * Creates a window, where you can choose a name for a new {@link Theme}.
* There are two versions of this Window. The first one is responsible for * choosing the name, the second one appears, the the name already exists. * - * @param parentClass The class, where this constructor is invoked. + * @param parent the dialog is launched with its location relative to this {@link SettingsScreen} + * @param newThemeAction is executed when a new theme name is entered + * @param modifyThemeAction is executed when an existing theme name is entered and confirmed * @since Envoy v0.3-alpha */ - public NewThemeScreen(ThemeCustomizationPanel parentClass) { + public NewThemeScreen(SettingsScreen parent, Consumer newThemeAction, Consumer modifyThemeAction) { + this.newThemeAction = newThemeAction; + this.modifyThemeAction = modifyThemeAction; + + setLocationRelativeTo(parent); setTitle("New Theme"); - setDimensions(true, parentClass); - setVisible(true); - setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); setModal(true); - // TODO: check modalitly - // setModalityType(DEFAULT_MODALITY_TYPE); + + setDimensions(true); + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); getContentPane().setLayout(new BorderLayout()); - { - standardPanel.setBackground(theme.getBackgroundColor()); - secondaryPanel.setBackground(theme.getBackgroundColor()); - loadStandardContent(theme, parentClass); - } + standardPanel.setBackground(theme.getBackgroundColor()); + secondaryPanel.setBackground(theme.getBackgroundColor()); + loadStandardContent(theme); } - private void setDimensions(boolean isStandard, ThemeCustomizationPanel parentClass) { - if (isStandard == true) { - setPreferredSize(new Dimension(300, 170)); - setMinimumSize(new Dimension(300, 170)); - setMaximumSize(new Dimension(300, 170)); - setBounds(parentClass.getLocation().x + (parentClass.getSize().width), - parentClass.getLocation().y + (parentClass.getSize().height / 2), - 300, - 170); - } else { - setPreferredSize(new Dimension(300, 225)); - setMinimumSize(new Dimension(300, 225)); - setMaximumSize(new Dimension(300, 225)); - setBounds(parentClass.getLocation().x + (parentClass.getSize().width), - parentClass.getLocation().y + (parentClass.getSize().height / 2), - 300, - 225); - } + private void setDimensions(boolean isStandard) { + Dimension size = isStandard ? new Dimension(300, 170) : new Dimension(300, 225); + setPreferredSize(size); + setMinimumSize(size); + setMaximumSize(size); } - private void loadStandardContent(Theme theme, ThemeCustomizationPanel parentClass) { + private void loadStandardContent(Theme theme) { getContentPane().removeAll(); // ContentPane @@ -139,23 +130,18 @@ public class NewThemeScreen extends JDialog { standardPanel.add(confirmButton, gbc_confirmButton); confirmButton.addActionListener((evt) -> { - if (!nameEnterTextArea.getText().isEmpty()) try { - if (Settings.getInstance().getThemes().containsKey(nameEnterTextArea.getText())) { - // load other panel - setDimensions(false, parentClass); - loadSecondaryPage(theme, parentClass); - } else { - parentClass.newTheme(nameEnterTextArea.getText()); - dispose(); - } - } catch (Exception e) { - logger.info("" + "Name could not be set! " + e); - e.printStackTrace(); + if (!nameEnterTextArea.getText().isEmpty()) if (Settings.getInstance().getThemes().containsKey(nameEnterTextArea.getText())) { + // load other panel + setDimensions(false); + loadSecondaryPage(theme); + } else { + newThemeAction.accept(nameEnterTextArea.getText()); + dispose(); } }); } - private void loadSecondaryPage(Theme theme, ThemeCustomizationPanel parentClass) { + private void loadSecondaryPage(Theme theme) { // ContentPane getContentPane().removeAll(); @@ -233,28 +219,8 @@ public class NewThemeScreen extends JDialog { secondaryPanel.add(overwrite, gbc_overwrite); - otherName.addActionListener((evt) -> { - try { - setDimensions(true, parentClass); - loadStandardContent(theme, parentClass); + otherName.addActionListener((evt) -> { setDimensions(true); loadStandardContent(theme); }); - } catch (Exception e) { - logger.info("Window could not be updated! " + e); - e.printStackTrace(); - } - - }); - - overwrite.addActionListener((evt) -> { - try { - dispose(); - parentClass.overwriteTheme(nameEnterTextArea.getText()); - - } catch (Exception e) { - logger.info("Error while overwriting the theme! " + e); - e.printStackTrace(); - } - - }); + overwrite.addActionListener((evt) -> { modifyThemeAction.accept(nameEnterTextArea.getText()); dispose(); }); } -} +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/settings/SettingsPanel.java b/src/main/java/envoy/client/ui/settings/SettingsPanel.java index 9b8f239..80469c5 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/SettingsPanel.java @@ -18,8 +18,18 @@ import javax.swing.JPanel; */ public abstract class SettingsPanel extends JPanel { + protected final SettingsScreen parent; + private static final long serialVersionUID = -3069212622468626050L; + /** + * Initializes a {@link SettingsPanel}. + * + * @param parent the {@link SettingsScreen} as a part of which this + * {@link SettingsPanel} is displayed + */ + public SettingsPanel(SettingsScreen parent) { this.parent = parent; } + /** * @return an {@link ActionListener} that should be invoked when the OK button * is pressed in the {@link SettingsScreen} diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 022f87f..611100f 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -93,7 +93,7 @@ public class SettingsScreen extends JDialog { if (settingsPanel != null) contentPanel.remove(settingsPanel); try { - settingsPanel = panels.get(option).getDeclaredConstructor().newInstance(); + settingsPanel = panels.get(option).getDeclaredConstructor(getClass()).newInstance(this); // Add selected settings panel contentPanel.add(settingsPanel, gbc_panel); @@ -162,8 +162,7 @@ public class SettingsScreen extends JDialog { EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme(((ThemeChangeEvent) evt).get())); setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - //setModal(true); - //TODO: check modalitly + setModal(true); } private void applyTheme(Theme theme) { diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 08d2357..9b1a85a 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -4,7 +4,6 @@ import java.awt.*; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; -import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; @@ -33,10 +32,11 @@ public class ThemeCustomizationPanel extends SettingsPanel { private JPanel colorsPanel = new JPanel(); - private String[] themeArray = Settings.getInstance().getThemes().keySet().toArray(new String[0]); - private JComboBox themes = new JComboBox<>(themeArray); - private Theme temporaryTheme, selectedTheme; - private boolean themeChanged = false; + private DefaultComboBoxModel themesModel = new DefaultComboBoxModel<>( + Settings.getInstance().getThemes().keySet().toArray(new String[0])); + private JComboBox themes = new JComboBox<>(themesModel); + private Theme temporaryTheme; + private boolean themeChanged; private final Insets insets = new Insets(5, 5, 5, 5); @@ -48,9 +48,12 @@ public class ThemeCustomizationPanel extends SettingsPanel { * the current {@link Theme} and create new themes as part of the * {@link SettingsScreen}. * + * @param parent the {@link SettingsScreen} as a part of which this + * {@link SettingsPanel} is displayed * @since Envoy v0.2-alpha */ - public ThemeCustomizationPanel() { + public ThemeCustomizationPanel(SettingsScreen parent) { + super(parent); temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); GridBagLayout gbl_themeLayout = new GridBagLayout(); @@ -64,16 +67,6 @@ public class ThemeCustomizationPanel extends SettingsPanel { themes.setSelectedItem(Settings.getInstance().getCurrentTheme()); - themes.addItemListener(new ItemListener() { - - @Override - public void itemStateChanged(ItemEvent e) { - String selectedValue = (String) themes.getSelectedItem(); - logger.log(Level.FINEST, selectedValue); - selectedTheme = Settings.getInstance().getThemes().get(selectedValue); - } - }); - GridBagConstraints gbc_themes = new GridBagConstraints(); gbc_themes.fill = GridBagConstraints.HORIZONTAL; gbc_themes.gridwidth = 2; @@ -106,26 +99,53 @@ public class ThemeCustomizationPanel extends SettingsPanel { add(colorsPanel, gbc_colorsPanel); colorsPanel.setBackground(theme.getCellColor()); + // Apply theme upon selection + themes.addItemListener(new ItemListener() { + + @Override + public void itemStateChanged(ItemEvent e) { + String selectedValue = (String) themes.getSelectedItem(); + logger.log(Level.FINEST, "Selected theme: " + selectedValue); + + final Theme currentTheme = Settings.getInstance().getTheme(selectedValue); + Settings.getInstance().setCurrentTheme(selectedValue); + EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); + } + }); + // Apply current theme applyTheme(theme); // Respond to theme changes - EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme(((ThemeChangeEvent) evt).get())); + EventBus.getInstance() + .register(ThemeChangeEvent.class, + (evt) -> { + final Theme currentTheme = ((ThemeChangeEvent) evt).get(); + temporaryTheme = new Theme("temporaryTheme", currentTheme); + applyTheme(currentTheme); + }); } @Override public ActionListener getOkButtonAction() { return (evt) -> { if (themeChanged) { - try { - new NewThemeScreen(this).setVisible(true); - } catch (Exception e) { - logger.info("New theme couldn't be created! " + e); - e.printStackTrace(); - } + new NewThemeScreen(parent, (name) -> { + // Create new theme + logger.log(Level.FINEST, name); + Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); + + // Add new theme name to combo box + themesModel.addElement(name); + + // Select new theme name + themes.setSelectedIndex(themesModel.getSize() - 1); + }, (name) -> { + // Modify theme + Settings.getInstance().getThemes().replace(name, new Theme(name, temporaryTheme)); + themes.setSelectedItem(name); + }).setVisible(true); themeChanged = false; - } else { - updateCurrentTheme(); } }; } @@ -139,13 +159,16 @@ public class ThemeCustomizationPanel extends SettingsPanel { themes.setBackground(theme.getInteractableBackgroundColor()); themes.setForeground(theme.getInteractableForegroundColor()); colorsPanel.setBackground(theme.getCellColor()); + + // Color panel + updateColorVariables(theme); + + revalidate(); + repaint(); } private void updateColorVariables(Theme theme) { - temporaryTheme = new Theme("temporaryTheme", theme); - colorsPanel.removeAll(); - buildCustomizeElements(theme); } @@ -155,7 +178,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3); buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor", 4); buildCustomizeElement(theme, theme.getMessageColorChat(), "Messages Chat", "messageColorChat", 5); - buildCustomizeElement(theme, theme.getDateColorChat(), "Date Chat", "dateColorCat", 6); + buildCustomizeElement(theme, theme.getDateColorChat(), "Date Chat", "dateColorChat", 6); buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor", 7); buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor", 8); buildCustomizeElement(theme, theme.getUserNameColor(), "User Names", "userNameColor", 9); @@ -175,21 +198,15 @@ public class ThemeCustomizationPanel extends SettingsPanel { button.setPreferredSize(new Dimension(25, 25)); button.addActionListener((evt) -> { - try { - java.awt.Color c = JColorChooser.showDialog(null, "Choose a color", color); - Color newColor = new Color(c.getRGB()); - if (newColor.getRGB() != color.getRGB()) { - logger.log(Level.FINEST, "New Color: " + String.valueOf(color.getRGB())); - // TODO: When Theme changed in same settings screen, color variable doesn't - // update + java.awt.Color c = JColorChooser.showDialog(null, "Choose a color", color); + if (c != null) { + Color newColor = new Color(c); + if (!color.equals(newColor)) { + logger.log(Level.FINEST, "New Color: " + newColor); temporaryTheme.setColor(colorName, newColor); themeChanged = true; } button.setBackground(newColor); - - } catch (Exception e) { - logger.info("An error occured while opening Color Chooser: " + e); - e.printStackTrace(); } }); @@ -211,48 +228,4 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.add(button, gbc_button); } - - private void updateCurrentTheme() { - Settings.getInstance().setCurrentTheme(selectedTheme.getThemeName()); - logger.log(Level.FINER, "Setting theme: " + selectedTheme.getThemeName()); - - final Theme currentTheme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - applyTheme(currentTheme); - updateColorVariables(currentTheme); - EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); - temporaryTheme = new Theme("temporaryTheme", currentTheme); - - revalidate(); - repaint(); - } - - /** - * Adds a new {@link Theme} to the theme map. - * - * @param name The name of the new {@link Theme}. - * @since Envoy v0.3-alpha - */ - public void newTheme(String name) { - logger.log(Level.FINEST, name); - Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); - themeArray = Arrays.copyOf(themeArray, themeArray.length + 1); - themeArray[themeArray.length - 1] = Settings.getInstance().getThemes().get(name).getThemeName(); - - themes.addItem(themeArray[themeArray.length - 1]); - themes.setSelectedIndex(themeArray.length - 1); - - updateCurrentTheme(); - } - - /** - * Overwrites a specific {@link Theme} located in the theme map and sets the selected {@link Theme} to this new {@link Theme}. - * - * @param key The name of the {@link Theme} to be overwritten. - * @since Envoy v0.3-alpha - */ - public void overwriteTheme(String key) { - Settings.getInstance().getThemes().replace(key, new Theme(key, temporaryTheme)); - selectedTheme = Settings.getInstance().getThemes().get(key); - updateCurrentTheme(); - } } \ No newline at end of file From 1870d7537196f532eee549d64e2b60fd66a598dc Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Fri, 27 Dec 2019 17:04:02 +0100 Subject: [PATCH 171/474] Added a v --- .../java/envoy/client/ui/settings/GeneralSettingsPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index d76d558..adafc2e 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -39,7 +39,7 @@ public class GeneralSettingsPanel extends SettingsPanel { * * @param parent the {@link SettingsScreen} as a part of which this * {@link SettingsPanel} is displayed - * @since Envoy 0.3-alpha + * @since Envoy v0.3-alpha */ public GeneralSettingsPanel(SettingsScreen parent) { super(parent); From 8e6ab074aa36ad6e70df088076e86f7e1ca47a51 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Fri, 27 Dec 2019 17:34:28 +0100 Subject: [PATCH 172/474] Fixed not updating theme when editing active theme bug. --- .../envoy/client/ui/settings/ThemeCustomizationPanel.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 9b1a85a..ba5da87 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -143,7 +143,11 @@ public class ThemeCustomizationPanel extends SettingsPanel { }, (name) -> { // Modify theme Settings.getInstance().getThemes().replace(name, new Theme(name, temporaryTheme)); - themes.setSelectedItem(name); + if(themes.getSelectedItem().equals(name)) { + EventBus.getInstance().dispatch(new ThemeChangeEvent(Settings.getInstance().getTheme(name))); + }else { + themes.setSelectedItem(name); + } }).setVisible(true); themeChanged = false; } From 4067be6bc2f99ab3b8d781dc0b36a9e94813e16d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 28 Dec 2019 22:20:43 +0200 Subject: [PATCH 173/474] Started integration of new server architecture * Removed JAX-RS dependency from POM * Changed version in POM to 0.3-alpha The errors that appear throughout LocalDB and Client are caused by the architecture change and will be removed in future commits. --- pom.xml | 14 +----- src/main/java/envoy/client/Chat.java | 4 +- src/main/java/envoy/client/Client.java | 5 +- src/main/java/envoy/client/LocalDB.java | 46 ++++--------------- .../client/event/MessageCreationEvent.java | 2 +- .../java/envoy/client/event/MessageEvent.java | 2 +- .../event/MessageModificationEvent.java | 2 +- src/main/java/envoy/client/ui/ChatWindow.java | 15 +++--- .../envoy/client/ui/MessageListRenderer.java | 20 ++++---- src/main/java/envoy/client/ui/Startup.java | 4 +- .../java/envoy/client/ui/StatusTrayIcon.java | 24 +++++----- .../envoy/client/ui/UserListRenderer.java | 4 +- 12 files changed, 51 insertions(+), 91 deletions(-) diff --git a/pom.xml b/pom.xml index d688c37..28e6f60 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ informatik-ag-ngl envoy-client - 0.0.1-SNAPSHOT + 0.3-alpha Envoy Client https://github.com/informatik-ag-ngl/envoy-client @@ -18,20 +18,10 @@ - - org.jboss.resteasy - resteasy-client - 4.1.1.Final - - - org.jboss.resteasy - resteasy-jaxb-provider - 4.3.1.Final - informatik-ag-ngl envoy-common - 0.0.1-SNAPSHOT + 0.2-alpha diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index daca33a..ef762c4 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -4,8 +4,8 @@ import java.io.Serializable; import javax.swing.DefaultListModel; -import envoy.schema.Message; -import envoy.schema.User; +import envoy.data.Message; +import envoy.data.User; /** * Represents a chat between two {@link User}s
diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index edc4839..1d27d5b 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -14,10 +14,8 @@ import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import envoy.client.util.EnvoyLog; +import envoy.data.User; import envoy.exception.EnvoyException; -import envoy.schema.ObjectFactory; -import envoy.schema.Sync; -import envoy.schema.User; /** * Project: envoy-client
@@ -31,7 +29,6 @@ import envoy.schema.User; */ public class Client { - private ObjectFactory objectFactory = new ObjectFactory(); private Config config; private User sender, recipient; private boolean online = false; diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index b5e3971..c86e3a0 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -2,10 +2,10 @@ package envoy.client; import java.io.File; import java.io.IOException; -import java.time.Instant; import java.util.*; import java.util.logging.Logger; +import javax.naming.spi.ObjectFactory; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; @@ -13,9 +13,9 @@ import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; import envoy.client.util.EnvoyLog; import envoy.client.util.SerializationUtils; +import envoy.data.Message; +import envoy.data.User; import envoy.exception.EnvoyException; -import envoy.schema.*; -import envoy.schema.Message.Metadata.MessageState; /** * Project: envoy-client
@@ -73,7 +73,7 @@ public class LocalDB { */ public void initializeDBFile() { if (user == null) throw new NullPointerException("Client user is null"); - localDBFile = new File(localDBDir, user.getID() + ".db"); + localDBFile = new File(localDBDir, user.getId() + ".db"); } /** @@ -107,32 +107,6 @@ public class LocalDB { */ public void loadChats() throws EnvoyException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } - /** - * Creates a {@link Message} object serializable to XML. - * - * @param textContent The content (text) of the message - * @param recipientID The recipient of the message - * @return prepared {@link Message} object - * @since Envoy v0.1-alpha - */ - public Message createMessage(String textContent, long recipientID) { - Message.Metadata metaData = objectFactory.createMessageMetadata(); - metaData.setSender(user.getID()); - metaData.setRecipient(recipientID); - metaData.setState(MessageState.WAITING); - metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); - - Message.Content content = objectFactory.createMessageContent(); - content.setType("text"); - content.setText(textContent); - - Message message = objectFactory.createMessage(); - message.setMetadata(metaData); - message.getContent().add(content); - - return message; - } - /** * Creates a {@link Sync} object filled with the changes that occurred to the * local database since the last synchronization. @@ -181,7 +155,7 @@ public class LocalDB { } else { // Update Messages in localDB to state RECEIVED for (Chat chat : getChats()) - if (chat.getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) + if (chat.getRecipient().getId() == returnSync.getMessages().get(i).getMetadata().getRecipient()) for (int j = 0; j < chat.getModel().getSize(); j++) if (chat.getModel().get(j).getMetadata().getMessageId() == returnSync.getMessages() .get(i) @@ -195,8 +169,8 @@ public class LocalDB { logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + "was initialized to be set to READ in localDB."); for (Chat chat : getChats()) - if (chat.getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - logger.info("Chat with: " + chat.getRecipient().getID() + "was selected."); + if (chat.getRecipient().getId() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + logger.info("Chat with: " + chat.getRecipient().getId() + "was selected."); for (int k = 0; k < chat.getModel().getSize(); k++) if (chat.getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() .get(i) @@ -215,7 +189,7 @@ public class LocalDB { // Updating UserStatus of all users in LocalDB for (User user : returnSync.getUsers()) for (Chat chat : getChats()) - if (user.getID() == chat.getRecipient().getID()) chat.getRecipient().setStatus(user.getStatus()); + if (user.getId() == chat.getRecipient().getId()) chat.getRecipient().setStatus(user.getStatus()); sync.getMessages().clear(); sync.getUsers().clear(); @@ -230,7 +204,7 @@ public class LocalDB { public void addUnreadMessagesToLocalDB() { for (Message message : unreadMessagesSync.getMessages()) for (Chat chat : getChats()) - if (message.getMetadata().getSender() == chat.getRecipient().getID()) { + if (message.getMetadata().getSender() == chat.getRecipient().getId()) { chat.appendMessage(message); break; } @@ -247,7 +221,7 @@ public class LocalDB { */ public void setMessagesToRead(Chat currentChat) { for (int i = currentChat.getModel().size() - 1; i >= 0; --i) - if (currentChat.getModel().get(i).getMetadata().getRecipient() != currentChat.getRecipient().getID()) + if (currentChat.getModel().get(i).getMetadata().getRecipient() != currentChat.getRecipient().getId()) if (currentChat.getModel().get(i).getMetadata().getState() == MessageState.RECEIVED) { currentChat.getModel().get(i).getMetadata().setState(MessageState.READ); readMessages.getMessages().add(currentChat.getModel().get(i)); diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java index 28f1b58..36397d9 100644 --- a/src/main/java/envoy/client/event/MessageCreationEvent.java +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -1,6 +1,6 @@ package envoy.client.event; -import envoy.schema.Message; +import envoy.data.Message; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java index 2e818e5..1dab6e7 100644 --- a/src/main/java/envoy/client/event/MessageEvent.java +++ b/src/main/java/envoy/client/event/MessageEvent.java @@ -1,6 +1,6 @@ package envoy.client.event; -import envoy.schema.Message; +import envoy.data.Message; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java index 0b83ef0..248c6f1 100644 --- a/src/main/java/envoy/client/event/MessageModificationEvent.java +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -1,6 +1,6 @@ package envoy.client.event; -import envoy.schema.Message; +import envoy.data.Message; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index dc68e10..5f8ff21 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -14,8 +14,9 @@ import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; -import envoy.schema.Message; -import envoy.schema.User; +import envoy.data.Message; +import envoy.data.TextMessage; +import envoy.data.User; /** * Project: envoy-client
@@ -164,7 +165,7 @@ public class ChatWindow extends JFrame { final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); - currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); + currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); // Set all unread messages in the chat to read readCurrentChat(); @@ -246,7 +247,7 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient().getID()); + final Message message = new TextMessage(0, localDB.getUser(), currentChat.getRecipient(), messageEnterTextArea.getText()); currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); @@ -275,7 +276,7 @@ public class ChatWindow extends JFrame { userListModel.addElement(user); // Check if user exists in local DB - if (localDB.getChats().stream().filter(c -> c.getRecipient().getID() == user.getID()).count() == 0) + if (localDB.getChats().stream().filter(c -> c.getRecipient().getId() == user.getId()).count() == 0) localDB.getChats().add(new Chat(user)); }); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); @@ -296,7 +297,7 @@ public class ChatWindow extends JFrame { // Synchronize try { - localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + localDB.applySync(client.sendSync(client.getSender().getId(), localDB.fillSync(client.getSender().getId()))); } catch (Exception e) { logger.log(Level.SEVERE, "Could not perform sync", e); } @@ -317,7 +318,7 @@ public class ChatWindow extends JFrame { private void updateUserStates() { for (int i = 0; i < userList.getModel().getSize(); i++) for (int j = 0; j < localDB.getChats().size(); j++) - if (userList.getModel().getElementAt(i).getID() == localDB.getChats().get(j).getRecipient().getID()) + if (userList.getModel().getElementAt(i).getId() == localDB.getChats().get(j).getRecipient().getId()) userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); } diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index ddd2230..967b1cc 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -8,7 +8,8 @@ import javax.swing.JList; import javax.swing.ListCellRenderer; import envoy.client.Settings; -import envoy.schema.Message; +import envoy.data.Message; +import envoy.data.TextMessage; /** * Defines how a message is displayed.
@@ -37,19 +38,18 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer

%s

%s :%s", dateColor, diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 8e57a08..1125030 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -12,8 +12,8 @@ import javax.swing.SwingUtilities; import envoy.client.*; import envoy.client.util.EnvoyLog; +import envoy.data.User; import envoy.exception.EnvoyException; -import envoy.schema.User; /** * Starts the Envoy client and prompts the user to enter their name.
@@ -129,7 +129,7 @@ public class Startup { JOptionPane.WARNING_MESSAGE); } - logger.info("Client user ID: " + client.getSender().getID()); + logger.info("Client user ID: " + client.getSender().getId()); // Save all users to the local database if (client.isOnline()) localDB.setUsers(client.getUsers()); diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 4670377..68427f6 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -1,21 +1,15 @@ package envoy.client.ui; -import java.awt.AWTException; -import java.awt.Image; -import java.awt.MenuItem; -import java.awt.PopupMenu; -import java.awt.SystemTray; -import java.awt.Toolkit; -import java.awt.TrayIcon; +import java.awt.*; import java.awt.TrayIcon.MessageType; -import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; +import envoy.data.Message; +import envoy.data.TextMessage; import envoy.exception.EnvoyException; -import envoy.schema.Message; /** * Project: envoy-client
@@ -81,10 +75,14 @@ public class StatusTrayIcon { trayIcon.addActionListener((evt) -> { focusTarget.setVisible(true); focusTarget.requestFocus(); }); // Start processing message events - EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { - if (displayMessages) - trayIcon.displayMessage("New message received", ((MessageCreationEvent) evt).get().getContent().get(0).getText(), MessageType.INFO); - }); + EventBus.getInstance() + .register(MessageCreationEvent.class, + (evt) -> { + // TODO: Handle other message types + if (displayMessages) trayIcon.displayMessage("New message received", + ((TextMessage) ((MessageCreationEvent) evt).get()).getContent(), + MessageType.INFO); + }); } /** diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index ca7214d..9441801 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -7,8 +7,8 @@ import javax.swing.JList; import javax.swing.ListCellRenderer; import envoy.client.Settings; -import envoy.schema.User; -import envoy.schema.User.UserStatus; +import envoy.data.User; +import envoy.data.User.UserStatus; /** * Defines how the {@code UserList} is displayed.
From 0efc8dbbc7a566cd0864a2c79a386d65aa51c541 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 29 Dec 2019 12:54:05 +0200 Subject: [PATCH 174/474] Working on handshake mechanism with login --- src/main/java/envoy/client/Client.java | 170 ++------- src/main/java/envoy/client/LocalDB.java | 338 +++++++++--------- src/main/java/envoy/client/Settings.java | 10 +- src/main/java/envoy/client/event/Event.java | 19 - .../java/envoy/client/event/EventBus.java | 81 ----- .../java/envoy/client/event/EventHandler.java | 18 - .../client/event/MessageCreationEvent.java | 1 + .../java/envoy/client/event/MessageEvent.java | 27 -- .../event/MessageModificationEvent.java | 1 + .../envoy/client/event/ThemeChangeEvent.java | 1 + src/main/java/envoy/client/ui/ChatWindow.java | 17 +- src/main/java/envoy/client/ui/Startup.java | 12 +- .../java/envoy/client/ui/StatusTrayIcon.java | 2 +- .../client/ui/settings/SettingsScreen.java | 2 +- .../ui/settings/ThemeCustomizationPanel.java | 2 +- .../envoy/client/util/SerializationUtils.java | 57 --- 16 files changed, 230 insertions(+), 528 deletions(-) delete mode 100644 src/main/java/envoy/client/event/Event.java delete mode 100644 src/main/java/envoy/client/event/EventBus.java delete mode 100644 src/main/java/envoy/client/event/EventHandler.java delete mode 100644 src/main/java/envoy/client/event/MessageEvent.java delete mode 100644 src/main/java/envoy/client/util/SerializationUtils.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 1d27d5b..6a4b754 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,21 +1,15 @@ package envoy.client; -import java.io.StringWriter; -import java.util.HashMap; +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; import java.util.Map; import java.util.logging.Logger; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Response; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; - import envoy.client.util.EnvoyLog; +import envoy.data.LoginCredentials; import envoy.data.User; -import envoy.exception.EnvoyException; +import envoy.util.SerializationUtils; /** * Project: envoy-client
@@ -29,43 +23,41 @@ import envoy.exception.EnvoyException; */ public class Client { - private Config config; - private User sender, recipient; - private boolean online = false; + private Socket socket; + private Config config = Config.getInstance(); + private User sender, recipient; + private boolean online; private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); - /** - * Initializes the client. At this state, the client user has yet to be - * initialized, which can be done by calling {@link Client#onlineInit(String)}. - * - * @param config The {@link Config} instance to use in this client - * @since Envoy v0.2-alpha - */ - public Client(Config config) { this.config = config; } - /** * Enters the online mode by acquiring a user ID from the server. * - * @param userName the name of the client user - * @throws EnvoyException if the online mode could not be entered or the request - * failed for some other reason + * @param credentials the login credentials of the user + * @throws IOException if the online mode could not be entered or the request + * failed for some other reason * @since Envoy v0.2-alpha */ - public void onlineInit(String userName) throws EnvoyException { - sender = getUser(userName); - online = true; - } + public void onlineInit(LoginCredentials credentials) throws IOException { + logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); + socket = new Socket(config.getServer(), config.getPort()); + logger.info("Successfully connected to server."); - private R post(String uri, T body, Class responseBodyClass) { - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client.target(uri); - Response response = target.request().post(Entity.entity(body, "application/xml")); - R responseBody = response.readEntity(responseBodyClass); - response.close(); - client.close(); + // Write login credentials + logger.finest("Sending login credentials..."); + SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); - return responseBody; + // Read response (user object) + InputStream in = socket.getInputStream(); + + // Read object + try { + sender = SerializationUtils.read(in, User.class); + } catch (ClassNotFoundException e) { + throw new IOException(e); + } + + online = true; } /** @@ -74,106 +66,8 @@ public class Client { * @since Envoy v0.2-alpha */ public Map getUsers() { - Sync sendSync = objectFactory.createSync(); - User user = objectFactory.createUser(); - user.setID(-1); - sendSync.getUsers().add(user); - - Sync returnSync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), - sendSync, - Sync.class); - - Map users = new HashMap<>(); - returnSync.getUsers().forEach(u -> users.put(u.getName(), u)); - return users; - } - - /** - * Returns a {@link User} with a specific id by name. - * - * @param name - the name of the {@link User} - * @return a {@link User} with the specified name - * @throws EnvoyException if the server does not return the requested ID - * @since Envoy v0.1-alpha - */ - private User getUser(String name) throws EnvoyException { - // Create a sync with only a user with the requested name - Sync senderSync = objectFactory.createSync(); - User user = objectFactory.createUser(); - user.setName(name); - senderSync.getUsers().add(user); - - try { - Sync sync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), - senderSync, - Sync.class); - - // Expecting a single user with an ID - if (sync.getUsers().size() == 1) { - online = true; - return sync.getUsers().get(0); - } else throw new EnvoyException("Unexpected response from Envoy Server"); - } catch (Exception e) { - throw new EnvoyException("Could not connect to server", e); - } - } - - /** - * Sends the "sync" Sync Object to the server and gets a "returnSync" Sync - * Object as response.
- * It is also used to get the own sender at the start of the client - * (Client sends "sync" Sync Object with single user in it(name: the name - * entered at login, id: 0, UserStatus:null))
- * and to get a complete list of all users saved on the server. - * (Client sends "sync" Sync Object with single user in it(name: "" (empty), id: - * -1, UserStatus:null))
- * This method also processes the response Sync Object.
- * It sorts its users and messages by specific variables and does certain things - * with them.
- *
- * Messages:
- * -State SENT: Update Local message(s) with State WAITING (add Message ID and - * change State to SENT). (server sends these informations to the client if - * message(s) with State WAITING were successfully sent to the server)
- * -State RECEIVED, SenderID != 0: Adds the unread Messages returned from the - * server in the latest sync to the "unreadMessagesSync" Sync Object.
- * -State RECEIVED, SenderID == 0: Update message(s) in localDB to state - * RECEIVED. - * (server sends these informations to the client if the other client received - * the message(s).)
- * -State READ: Update message(s) in the LocalDB to state READ. (server sends - * these informations to the client if the other client read - * the message(s).)
- *
- * Users:
- * Updating UserStatus of all users in LocalDB. (Server sends all users with - * their updated UserStatus to the client.)
- * - * @param userId the id of the {@link Client} who sends the {@link Sync} - * @param sync the sync object (yet to be converted from java class to - * sync.xml) - * @return a returnSync.xml file - * @throws EnvoyException if the client is not in online mode - * @since Envoy v0.1-alpha - */ - public Sync sendSync(long userId, Sync sync) throws EnvoyException { - if(!isOnline()) - throw new EnvoyException("Client is not in online mode"); - // Print sync XML to console - JAXBContext jc; - try { - jc = JAXBContext.newInstance("envoy.schema"); - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - StringWriter stringWriter = new StringWriter(); - m.marshal(sync, stringWriter); - logger.fine("Sending sync:\n" + stringWriter.toString()); - } catch (JAXBException e) { - e.printStackTrace(); - } - - // Send sync - return post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), sync, Sync.class); + // TODO + return null; } /** diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index c86e3a0..d550c3a 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -5,17 +5,9 @@ import java.io.IOException; import java.util.*; import java.util.logging.Logger; -import javax.naming.spi.ObjectFactory; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeFactory; - -import envoy.client.event.EventBus; -import envoy.client.event.MessageCreationEvent; import envoy.client.util.EnvoyLog; -import envoy.client.util.SerializationUtils; -import envoy.data.Message; import envoy.data.User; -import envoy.exception.EnvoyException; +import envoy.util.SerializationUtils; /** * Project: envoy-client
@@ -33,13 +25,6 @@ public class LocalDB { private Map users = new HashMap<>(); private List chats = new ArrayList<>(); - private ObjectFactory objectFactory = new ObjectFactory(); - private DatatypeFactory datatypeFactory; - - private Sync unreadMessagesSync = objectFactory.createSync(); - private Sync sync = objectFactory.createSync(); - private Sync readMessages = objectFactory.createSync(); - private static final Logger logger = EnvoyLog.getLogger(LocalDB.class.getSimpleName()); /** @@ -53,12 +38,6 @@ public class LocalDB { public LocalDB(File localDBDir) throws IOException { this.localDBDir = localDBDir; - try { - datatypeFactory = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException e) { - e.printStackTrace(); - } - // Initialize local database directory if (localDBDir.exists() && !localDBDir.isDirectory()) throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); @@ -93,162 +72,181 @@ public class LocalDB { /** * Loads all users that are stored in the local database. - * - * @throws EnvoyException if the loading process failed + * + * @throws IOException if the loading process failed + * @throws ClassNotFoundException if the loading process failed * @since Envoy v0.2-alpha */ - public void loadUsers() throws EnvoyException { users = SerializationUtils.read(usersFile, HashMap.class); } + public void loadUsers() throws ClassNotFoundException, IOException { users = SerializationUtils.read(usersFile, HashMap.class); } /** * Loads all chats saved by Envoy for the client user. - * - * @throws EnvoyException if the loading process failed + * + * @throws IOException if the loading process failed + * @throws ClassNotFoundException if the loading process failed * @since Envoy v0.1-alpha */ - public void loadChats() throws EnvoyException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } + public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } - /** - * Creates a {@link Sync} object filled with the changes that occurred to the - * local database since the last synchronization. - * - * @param userId the ID of the user that is synchronized by this client - * @return {@link Sync} object filled with the current changes - * @since Envoy v0.1-alpha - */ - public Sync fillSync(long userId) { - addWaitingMessagesToSync(); - - sync.getMessages().addAll(readMessages.getMessages()); - readMessages.getMessages().clear(); - - logger.finest(String.format("Filled sync with %d messages.", sync.getMessages().size())); - return sync; - } - - /** - * Applies the changes carried by a {@link Sync} object to the local database - * - * @param returnSync the {@link Sync} object to apply - * @since Envoy v0.1-alpha - */ - public void applySync(Sync returnSync) { - for (int i = 0; i < returnSync.getMessages().size(); i++) { - - // The message has an ID - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0) { - - // Messages are processes differently corresponding to their state - switch (returnSync.getMessages().get(i).getMetadata().getState()) { - case SENT: - // Update previously waiting and now sent messages that were assigned an ID by - // the server - sync.getMessages().get(i).getMetadata().setMessageId(returnSync.getMessages().get(i).getMetadata().getMessageId()); - sync.getMessages().get(i).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - break; - case RECEIVED: - if (returnSync.getMessages().get(i).getMetadata().getSender() != 0) { - // these are the unread Messages from the server - unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); - - // Create and dispatch message creation event - EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); - } else { - // Update Messages in localDB to state RECEIVED - for (Chat chat : getChats()) - if (chat.getRecipient().getId() == returnSync.getMessages().get(i).getMetadata().getRecipient()) - for (int j = 0; j < chat.getModel().getSize(); j++) - if (chat.getModel().get(j).getMetadata().getMessageId() == returnSync.getMessages() - .get(i) - .getMetadata() - .getMessageId()) - chat.getModel().get(j).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - } - break; - case READ: - // Update local Messages to state READ - logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() - + "was initialized to be set to READ in localDB."); - for (Chat chat : getChats()) - if (chat.getRecipient().getId() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - logger.info("Chat with: " + chat.getRecipient().getId() + "was selected."); - for (int k = 0; k < chat.getModel().getSize(); k++) - if (chat.getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() - .get(i) - .getMetadata() - .getMessageId()) { - logger.info("Message with ID: " + chat.getModel().get(k).getMetadata().getMessageId() + "was selected."); - chat.getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - logger.info("Message State is now: " + chat.getModel().get(k).getMetadata().getState()); - } - } - break; - } - } - } - - // Updating UserStatus of all users in LocalDB - for (User user : returnSync.getUsers()) - for (Chat chat : getChats()) - if (user.getId() == chat.getRecipient().getId()) chat.getRecipient().setStatus(user.getStatus()); - - sync.getMessages().clear(); - sync.getUsers().clear(); - } - - /** - * Adds the unread messages returned from the server in the latest sync to the - * right chats in the LocalDB. - * - * @since Envoy v0.1-alpha - */ - public void addUnreadMessagesToLocalDB() { - for (Message message : unreadMessagesSync.getMessages()) - for (Chat chat : getChats()) - if (message.getMetadata().getSender() == chat.getRecipient().getId()) { - chat.appendMessage(message); - break; - } - } - - /** - * Changes all messages with state {@code RECEIVED} of a specific chat to state - * {@code READ}. - *
- * Adds these messages to the {@code readMessages} {@link Sync} object. - * - * @param currentChat the {@link Chat} that was just opened - * @since Envoy v0.1-alpha - */ - public void setMessagesToRead(Chat currentChat) { - for (int i = currentChat.getModel().size() - 1; i >= 0; --i) - if (currentChat.getModel().get(i).getMetadata().getRecipient() != currentChat.getRecipient().getId()) - if (currentChat.getModel().get(i).getMetadata().getState() == MessageState.RECEIVED) { - currentChat.getModel().get(i).getMetadata().setState(MessageState.READ); - readMessages.getMessages().add(currentChat.getModel().get(i)); - } else break; - } - - /** - * Adds all messages with state {@code WAITING} from the {@link LocalDB} to the - * {@link Sync} object. - * - * @since Envoy v0.1-alpha - */ - private void addWaitingMessagesToSync() { - for (Chat chat : getChats()) - for (int i = 0; i < chat.getModel().size(); i++) - if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) { - logger.info("Got Waiting Message"); - sync.getMessages().add(chat.getModel().get(i)); - } - } - - /** - * Clears the {@code unreadMessagesSync} {@link Sync} object. - * - * @since Envoy v0.1-alpha - */ - public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } + // /** + // * Creates a {@link Sync} object filled with the changes that occurred to the + // * local database since the last synchronization. + // * + // * @param userId the ID of the user that is synchronized by this client + // * @return {@link Sync} object filled with the current changes + // * @since Envoy v0.1-alpha + // */ + // public Sync fillSync(long userId) { + // addWaitingMessagesToSync(); + // + // sync.getMessages().addAll(readMessages.getMessages()); + // readMessages.getMessages().clear(); + // + // logger.finest(String.format("Filled sync with %d messages.", + // sync.getMessages().size())); + // return sync; + // } + // + // /** + // * Applies the changes carried by a {@link Sync} object to the local database + // * + // * @param returnSync the {@link Sync} object to apply + // * @since Envoy v0.1-alpha + // */ + // public void applySync(Sync returnSync) { + // for (int i = 0; i < returnSync.getMessages().size(); i++) { + // + // // The message has an ID + // if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0) { + // + // // Messages are processes differently corresponding to their state + // switch (returnSync.getMessages().get(i).getMetadata().getState()) { + // case SENT: + // // Update previously waiting and now sent messages that were assigned an ID + // by + // // the server + // sync.getMessages().get(i).getMetadata().setMessageId(returnSync.getMessages().get(i).getMetadata().getMessageId()); + // sync.getMessages().get(i).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + // break; + // case RECEIVED: + // if (returnSync.getMessages().get(i).getMetadata().getSender() != 0) { + // // these are the unread Messages from the server + // unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); + // + // // Create and dispatch message creation event + // EventBus.getInstance().dispatch(new + // MessageCreationEvent(returnSync.getMessages().get(i))); + // } else { + // // Update Messages in localDB to state RECEIVED + // for (Chat chat : getChats()) + // if (chat.getRecipient().getId() == + // returnSync.getMessages().get(i).getMetadata().getRecipient()) + // for (int j = 0; j < chat.getModel().getSize(); j++) + // if (chat.getModel().get(j).getMetadata().getMessageId() == + // returnSync.getMessages() + // .get(i) + // .getMetadata() + // .getMessageId()) + // chat.getModel().get(j).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + // } + // break; + // case READ: + // // Update local Messages to state READ + // logger.info("Message with ID: " + + // returnSync.getMessages().get(i).getMetadata().getMessageId() + // + "was initialized to be set to READ in localDB."); + // for (Chat chat : getChats()) + // if (chat.getRecipient().getId() == + // returnSync.getMessages().get(i).getMetadata().getRecipient()) { + // logger.info("Chat with: " + chat.getRecipient().getId() + "was selected."); + // for (int k = 0; k < chat.getModel().getSize(); k++) + // if (chat.getModel().get(k).getMetadata().getMessageId() == + // returnSync.getMessages() + // .get(i) + // .getMetadata() + // .getMessageId()) { + // logger.info("Message with ID: " + + // chat.getModel().get(k).getMetadata().getMessageId() + "was selected."); + // chat.getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + // logger.info("Message State is now: " + + // chat.getModel().get(k).getMetadata().getState()); + // } + // } + // break; + // } + // } + // } + // + // // Updating UserStatus of all users in LocalDB + // for (User user : returnSync.getUsers()) + // for (Chat chat : getChats()) + // if (user.getId() == chat.getRecipient().getId()) + // chat.getRecipient().setStatus(user.getStatus()); + // + // sync.getMessages().clear(); + // sync.getUsers().clear(); + // } + // + // /** + // * Adds the unread messages returned from the server in the latest sync to the + // * right chats in the LocalDB. + // * + // * @since Envoy v0.1-alpha + // */ + // public void addUnreadMessagesToLocalDB() { + // for (Message message : unreadMessagesSync.getMessages()) + // for (Chat chat : getChats()) + // if (message.getMetadata().getSender() == chat.getRecipient().getId()) { + // chat.appendMessage(message); + // break; + // } + // } + // + // /** + // * Changes all messages with state {@code RECEIVED} of a specific chat to + // state + // * {@code READ}. + // *
+ // * Adds these messages to the {@code readMessages} {@link Sync} object. + // * + // * @param currentChat the {@link Chat} that was just opened + // * @since Envoy v0.1-alpha + // */ + // public void setMessagesToRead(Chat currentChat) { + // for (int i = currentChat.getModel().size() - 1; i >= 0; --i) + // if (currentChat.getModel().get(i).getMetadata().getRecipient() != + // currentChat.getRecipient().getId()) + // if (currentChat.getModel().get(i).getMetadata().getState() == + // MessageState.RECEIVED) { + // currentChat.getModel().get(i).getMetadata().setState(MessageState.READ); + // readMessages.getMessages().add(currentChat.getModel().get(i)); + // } else break; + // } + // + // /** + // * Adds all messages with state {@code WAITING} from the {@link LocalDB} to + // the + // * {@link Sync} object. + // * + // * @since Envoy v0.1-alpha + // */ + // private void addWaitingMessagesToSync() { + // for (Chat chat : getChats()) + // for (int i = 0; i < chat.getModel().size(); i++) + // if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) + // { + // logger.info("Got Waiting Message"); + // sync.getMessages().add(chat.getModel().get(i)); + // } + // } + // + // /** + // * Clears the {@code unreadMessagesSync} {@link Sync} object. + // * + // * @since Envoy v0.1-alpha + // */ + // public void clearUnreadMessagesSync() { + // unreadMessagesSync.getMessages().clear(); } /** * @return a {@code Map} of all users stored locally with their diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index cdecc33..ef451d0 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -1,14 +1,14 @@ package envoy.client; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; import envoy.client.ui.Color; import envoy.client.ui.Theme; -import envoy.client.util.SerializationUtils; -import envoy.exception.EnvoyException; +import envoy.util.SerializationUtils; /** * Manages all application settings, which are different objects that can be @@ -55,7 +55,7 @@ public class Settings { // Load settings from settings file try { items = SerializationUtils.read(settingsFile, HashMap.class); - } catch (EnvoyException e) { + } catch (ClassNotFoundException | IOException e) { items = new HashMap<>(); } supplementDefaults(); @@ -63,7 +63,7 @@ public class Settings { // Load themes from theme file try { themes = SerializationUtils.read(themeFile, HashMap.class); - } catch (EnvoyException e1) { + } catch (ClassNotFoundException | IOException e1) { themes = new HashMap<>(); setCurrentTheme("dark"); } diff --git a/src/main/java/envoy/client/event/Event.java b/src/main/java/envoy/client/event/Event.java deleted file mode 100644 index 8e5393a..0000000 --- a/src/main/java/envoy/client/event/Event.java +++ /dev/null @@ -1,19 +0,0 @@ -package envoy.client.event; - -/** - * Project: envoy-client
- * File: Event.java
- * Created: 04.12.2019
- * - * @author Kai S. K. Engelbart - * @param the type of the Event - * @since Envoy v0.2-alpha - */ -public interface Event { - - /** - * @return the data associated with this event - */ - T get(); -} - diff --git a/src/main/java/envoy/client/event/EventBus.java b/src/main/java/envoy/client/event/EventBus.java deleted file mode 100644 index 06b385f..0000000 --- a/src/main/java/envoy/client/event/EventBus.java +++ /dev/null @@ -1,81 +0,0 @@ -package envoy.client.event; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * This class handles events by allowing {@link EventHandler} object to register - * themselves and then be notified about certain events dispatched by the event - * bus.
- *
- * The event bus is a singleton and can be used across the entire application to - * guarantee the propagation of events.
- * - * Project: envoy-client
- * File: EventBus.java
- * Created: 04.12.2019
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha - */ -public class EventBus { - - /** - * Contains all {@link EventHandler} instances registered at this - * {@link EventBus} as values mapped to by their supported {@link Event} - * classes. - */ - private Map>, List> handlers = new HashMap<>(); - - /** - * The singleton instance of this {@link EventBus} that is used across the - * entire application. - */ - private static EventBus eventBus = new EventBus(); - - /** - * This constructor is not accessible from outside this class because a - * singleton instance of it is provided by the {@link EventBus#getInstance()} - * method. - */ - private EventBus() {} - - /** - * @return the singleton instance of the {@link EventBus} - * @since Envoy v0.2-alpha - */ - public static EventBus getInstance() { return eventBus; } - - /** - * Registers an {@link EventHandler} to be notified when a - * {@link Event} of a certain type is dispatched. - * - * @param eventClass the class which the {@link EventHandler} is subscribed to - * @param handler the {@link EventHandler} to register - * @since Envoy v0.2-alpha - */ - public void register(Class> eventClass, EventHandler handler) { - if (!handlers.containsKey(eventClass)) handlers.put(eventClass, new ArrayList<>()); - handlers.get(eventClass).add(handler); - } - - /** - * Dispatches a {@link Event} to every {@link EventHandler} subscribed to it. - * - * @param event the {@link Event} to dispatch - * @since Envoy v0.2-alpha - */ - public void dispatch(Event event) { - handlers.keySet().stream().filter(event.getClass()::isAssignableFrom).map(handlers::get).flatMap(List::stream).forEach(h -> h.handle(event)); - } - - /** - * @return a map of all {@link EventHandler} instances currently registered at - * this {@link EventBus} with the {@link Event} classes they are - * subscribed to as keys - * @since Envoy v0.2-alpha - */ - public Map>, List> getHandlers() { return handlers; } -} diff --git a/src/main/java/envoy/client/event/EventHandler.java b/src/main/java/envoy/client/event/EventHandler.java deleted file mode 100644 index ef3daea..0000000 --- a/src/main/java/envoy/client/event/EventHandler.java +++ /dev/null @@ -1,18 +0,0 @@ -package envoy.client.event; - -/** - * Project: envoy-clientChess
- * File: EventHandler.javaEvent.java
- * Created: 04.12.2019
- * - * @author Kai S. K. Engelbart - */ -public interface EventHandler { - - /** - * Consumes an event dispatched by the event bus. - * - * @param event The event dispatched by the event bus, only of supported type - */ - void handle(Event event); -} diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java index 36397d9..d2e372d 100644 --- a/src/main/java/envoy/client/event/MessageCreationEvent.java +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -1,6 +1,7 @@ package envoy.client.event; import envoy.data.Message; +import envoy.event.MessageEvent; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java deleted file mode 100644 index 1dab6e7..0000000 --- a/src/main/java/envoy/client/event/MessageEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package envoy.client.event; - -import envoy.data.Message; - -/** - * Project: envoy-client
- * File: MessageCreationEvent.java
- * Created: 4 Dec 2019
- * - * @author Kai S. K. Engelbart - */ -public class MessageEvent implements Event { - - protected final Message message; - - /** - * Initializes a {@link MessageEvent} conveying information about a - * {@link Message} object. - * - * @param message the {@link Message} object to attach to this event - * @since Envoy v0.2-alpha - */ - public MessageEvent(Message message) { this.message = message; } - - @Override - public Message get() { return message; } -} diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java index 248c6f1..a5b7c41 100644 --- a/src/main/java/envoy/client/event/MessageModificationEvent.java +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -1,6 +1,7 @@ package envoy.client.event; import envoy.data.Message; +import envoy.event.MessageEvent; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/event/ThemeChangeEvent.java b/src/main/java/envoy/client/event/ThemeChangeEvent.java index ac07aa1..adb9707 100644 --- a/src/main/java/envoy/client/event/ThemeChangeEvent.java +++ b/src/main/java/envoy/client/event/ThemeChangeEvent.java @@ -1,6 +1,7 @@ package envoy.client.event; import envoy.client.ui.Theme; +import envoy.event.Event; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 5f8ff21..289fdd6 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -10,13 +10,13 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; import envoy.client.*; -import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; import envoy.data.Message; import envoy.data.TextMessage; import envoy.data.User; +import envoy.event.EventBus; /** * Project: envoy-client
@@ -297,14 +297,15 @@ public class ChatWindow extends JFrame { // Synchronize try { - localDB.applySync(client.sendSync(client.getSender().getId(), localDB.fillSync(client.getSender().getId()))); + // localDB.applySync(client.sendSync(client.getSender().getId(), + // localDB.fillSync(client.getSender().getId()))); } catch (Exception e) { logger.log(Level.SEVERE, "Could not perform sync", e); } - // Process unread messages - localDB.addUnreadMessagesToLocalDB(); - localDB.clearUnreadMessagesSync(); + // TODO: Process unread messages + // localDB.addUnreadMessagesToLocalDB(); + // localDB.clearUnreadMessagesSync(); // Mark unread messages as read when they are in the current chat readCurrentChat(); @@ -325,7 +326,11 @@ public class ChatWindow extends JFrame { /** * Marks messages in the current chat as {@code READ}. */ - private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } + private void readCurrentChat() { + if (currentChat != null) { + // TODO: localDB.setMessagesToRead(currentChat); + } + } /** * Sets the {@link Client} used by this {@link ChatWindow}. If the client is diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 1125030..2faaa1a 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -12,6 +12,7 @@ import javax.swing.SwingUtilities; import envoy.client.*; import envoy.client.util.EnvoyLog; +import envoy.data.LoginCredentials; import envoy.data.User; import envoy.exception.EnvoyException; @@ -75,6 +76,9 @@ public class Startup { logger.severe("User name is not set or empty. Exiting..."); System.exit(1); } + + // TODO: create dialog + String pass = JOptionPane.showInputDialog("Enter password"); // Initialize the local database LocalDB localDB; @@ -91,10 +95,10 @@ public class Startup { // Acquire the client user (with ID) either from the server or from the local // database, which triggers offline mode - Client client = new Client(config); + Client client = new Client(); try { // Try entering online mode first - client.onlineInit(userName); + client.onlineInit(new LoginCredentials(userName, pass.toCharArray())); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); try { @@ -120,8 +124,8 @@ public class Startup { // Initialize chats in local database try { localDB.initializeDBFile(); - localDB.loadChats(); - } catch (EnvoyException e) { + // TODO: localDB.loadChats(); + } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 68427f6..a403799 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -5,10 +5,10 @@ import java.awt.TrayIcon.MessageType; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; import envoy.data.Message; import envoy.data.TextMessage; +import envoy.event.EventBus; import envoy.exception.EnvoyException; /** diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 611100f..533200f 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -10,11 +10,11 @@ import java.util.logging.Logger; import javax.swing.*; import envoy.client.Settings; -import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.PrimaryButton; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; +import envoy.event.EventBus; /** * This class provides the GUI to change the user specific settings.
diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index ba5da87..9d4c6be 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -10,11 +10,11 @@ import java.util.logging.Logger; import javax.swing.*; import envoy.client.Settings; -import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.Color; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; +import envoy.event.EventBus; /** * Displays GUI components that allow changing the current {@Theme} and creating diff --git a/src/main/java/envoy/client/util/SerializationUtils.java b/src/main/java/envoy/client/util/SerializationUtils.java deleted file mode 100644 index f0cc70f..0000000 --- a/src/main/java/envoy/client/util/SerializationUtils.java +++ /dev/null @@ -1,57 +0,0 @@ -package envoy.client.util; - -import java.io.*; - -import envoy.exception.EnvoyException; - -/** - * Project: envoy-clientChess
- * File: SerializationUtils.javaEvent.java
- * Created: 23.12.2019
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha - */ -public class SerializationUtils { - - private SerializationUtils() {} - - /** - * Deserializes an arbitrary {@link Serializable} object from a file. - * - * @param the type of the object to deserialize - * @param file the file deserialize from - * @param serializedClass the class of the object to deserialize - * @return the deserialized object - * @throws EnvoyException if an error occurred during deserialization - * @since Envoy v0.3-alpha - */ - public static T read(File file, Class serializedClass) throws EnvoyException { - if (file == null) throw new NullPointerException("File is null"); - try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { - return serializedClass.cast(in.readObject()); - } catch (ClassNotFoundException | IOException e) { - throw new EnvoyException("Could not load serialized object", e); - } - } - - /** - * Serializes an arbitrary object to a file. - * - * @param file the file to serialize to - * @param obj the object to serialize - * @throws IOException if an error occurred during serialization - * @since Envoy v0.3-alpha - */ - public static void write(File file, Object obj) throws IOException { - if (file == null) throw new NullPointerException("File is null"); - if (obj == null) throw new NullPointerException("Object to serialize is null"); - if (!file.exists()) { - file.getParentFile().mkdirs(); - file.createNewFile(); - } - try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) { - out.writeObject(obj); - } - } -} \ No newline at end of file From c06a2e8c375c8b3eda344ba651d4569ea3de4a4f Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 30 Dec 2019 18:18:03 +0200 Subject: [PATCH 175/474] Receiving objects from server on separate thread --- src/main/java/envoy/client/Client.java | 38 ++++++++------ .../java/envoy/client/ObjectProcessor.java | 15 ++++++ src/main/java/envoy/client/Receiver.java | 50 +++++++++++++++++++ src/main/java/envoy/client/ui/Startup.java | 1 + 4 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 src/main/java/envoy/client/ObjectProcessor.java create mode 100644 src/main/java/envoy/client/Receiver.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 6a4b754..a037e8c 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,7 +1,5 @@ package envoy.client; -import java.io.IOException; -import java.io.InputStream; import java.net.Socket; import java.util.Map; import java.util.logging.Logger; @@ -9,6 +7,7 @@ import java.util.logging.Logger; import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; import envoy.data.User; +import envoy.exception.EnvoyException; import envoy.util.SerializationUtils; /** @@ -23,10 +22,11 @@ import envoy.util.SerializationUtils; */ public class Client { - private Socket socket; - private Config config = Config.getInstance(); - private User sender, recipient; - private boolean online; + private Socket socket; + private Config config = Config.getInstance(); + private volatile User sender; + private User recipient; + private boolean online; private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); @@ -34,11 +34,11 @@ public class Client { * Enters the online mode by acquiring a user ID from the server. * * @param credentials the login credentials of the user - * @throws IOException if the online mode could not be entered or the request - * failed for some other reason + * @throws Exception if the online mode could not be entered or the request + * failed for some other reason * @since Envoy v0.2-alpha */ - public void onlineInit(LoginCredentials credentials) throws IOException { + public void onlineInit(LoginCredentials credentials) throws Exception { logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); socket = new Socket(config.getServer(), config.getPort()); logger.info("Successfully connected to server."); @@ -47,14 +47,20 @@ public class Client { logger.finest("Sending login credentials..."); SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); - // Read response (user object) - InputStream in = socket.getInputStream(); + // Create message receiver + Receiver receiver = new Receiver(socket.getInputStream()); - // Read object - try { - sender = SerializationUtils.read(in, User.class); - } catch (ClassNotFoundException e) { - throw new IOException(e); + // Register user creation processor + receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); + + // Start receiver + new Thread(receiver).start(); + + // Wait for a maximum of five seconds to acquire the sender object + long start = System.currentTimeMillis(); + while (sender == null) { + if (System.currentTimeMillis() - start > 5000) throw new EnvoyException("Did not log in after 5 seconds"); + Thread.sleep(500); } online = true; diff --git a/src/main/java/envoy/client/ObjectProcessor.java b/src/main/java/envoy/client/ObjectProcessor.java new file mode 100644 index 0000000..b0aed2d --- /dev/null +++ b/src/main/java/envoy/client/ObjectProcessor.java @@ -0,0 +1,15 @@ +package envoy.client; + + +/** + * Project: envoy-client
+ * File: ObjectProcessor.java
+ * Created: 30.12.2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public interface ObjectProcessor { + + void process(T input); +} \ No newline at end of file diff --git a/src/main/java/envoy/client/Receiver.java b/src/main/java/envoy/client/Receiver.java new file mode 100644 index 0000000..64a4655 --- /dev/null +++ b/src/main/java/envoy/client/Receiver.java @@ -0,0 +1,50 @@ +package envoy.client; + +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import envoy.client.util.EnvoyLog; + +/** + * Project: envoy-client
+ * File: Receiver.java
+ * Created: 30.12.2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class Receiver implements Runnable { + + private InputStream in; + private Map, ObjectProcessor> processors = new HashMap<>(); + + private static final Logger logger = EnvoyLog.getLogger(Receiver.class.getSimpleName()); + + public Receiver(InputStream in) { this.in = in; } + + @SuppressWarnings("unchecked") + @Override + public void run() { + try (ObjectInputStream oin = new ObjectInputStream(in)) { + while (true) { + Object obj = oin.readObject(); + logger.finest("Received object " + obj); + + // Get appropriate processor + ObjectProcessor processor = processors.get(obj.getClass()); + if (processor == null) + logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); + else + processor.process(obj); + } + } catch(Exception e) { + logger.log(Level.SEVERE, "Error on receiver thread", e); + } + } + + public void registerProcessor(Class processorClass, ObjectProcessor processor) { processors.put(processorClass, processor); } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 2faaa1a..1a2c96e 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -101,6 +101,7 @@ public class Startup { client.onlineInit(new LoginCredentials(userName, pass.toCharArray())); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); + e1.printStackTrace(); try { // Try entering offline mode localDB.loadUsers(); From 22ccddcc39c07fc4a01bef0d6e2617dd68c7db1c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 31 Dec 2019 11:27:52 +0200 Subject: [PATCH 176/474] Integrated the new Message class from envoy-common --- src/main/java/envoy/client/ui/ChatWindow.java | 4 ++-- src/main/java/envoy/client/ui/MessageListRenderer.java | 10 ++++------ src/main/java/envoy/client/ui/StatusTrayIcon.java | 8 +++----- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 289fdd6..591be9f 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -14,7 +14,7 @@ import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; import envoy.data.Message; -import envoy.data.TextMessage; +import envoy.data.MessageBuilder; import envoy.data.User; import envoy.event.EventBus; @@ -247,7 +247,7 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { // Create and send message object - final Message message = new TextMessage(0, localDB.getUser(), currentChat.getRecipient(), messageEnterTextArea.getText()); + final Message message = new MessageBuilder(localDB.getUser(), currentChat.getRecipient()).setText(messageEnterTextArea.getText()).build(); currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 967b1cc..33f36f9 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -9,7 +9,6 @@ import javax.swing.ListCellRenderer; import envoy.client.Settings; import envoy.data.Message; -import envoy.data.TextMessage; /** * Defines how a message is displayed.
@@ -38,12 +37,11 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer { // TODO: Handle other message types - if (displayMessages) trayIcon.displayMessage("New message received", - ((TextMessage) ((MessageCreationEvent) evt).get()).getContent(), - MessageType.INFO); + if (displayMessages) + trayIcon.displayMessage("New message received", ((MessageCreationEvent) evt).get().getText(), MessageType.INFO); }); } @@ -99,4 +97,4 @@ public class StatusTrayIcon { throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); } } -} +} \ No newline at end of file From 1fec53f35acc11ba4d950cc74bd05b6277829140 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 31 Dec 2019 11:57:11 +0200 Subject: [PATCH 177/474] Added Client#sendMessage(Message), closing socket on exit --- src/main/java/envoy/client/Client.java | 45 +++++++++++++++---- .../java/envoy/client/ObjectProcessor.java | 15 ------- src/main/java/envoy/client/Receiver.java | 27 ++++++++--- src/main/java/envoy/client/ui/ChatWindow.java | 7 ++- src/main/java/envoy/client/ui/Startup.java | 31 ++++++++----- 5 files changed, 81 insertions(+), 44 deletions(-) delete mode 100644 src/main/java/envoy/client/ObjectProcessor.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index a037e8c..b87f31d 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,11 +1,14 @@ package envoy.client; +import java.io.Closeable; +import java.io.IOException; import java.net.Socket; import java.util.Map; import java.util.logging.Logger; import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; +import envoy.data.Message; import envoy.data.User; import envoy.exception.EnvoyException; import envoy.util.SerializationUtils; @@ -20,13 +23,16 @@ import envoy.util.SerializationUtils; * @author Leon Hofmeister * @since Envoy v0.1-alpha */ -public class Client { +public class Client implements Closeable { + + private Socket socket; + private Receiver receiver; + private boolean online; - private Socket socket; - private Config config = Config.getInstance(); private volatile User sender; private User recipient; - private boolean online; + + private Config config = Config.getInstance(); private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); @@ -39,20 +45,21 @@ public class Client { * @since Envoy v0.2-alpha */ public void onlineInit(LoginCredentials credentials) throws Exception { + // Establish TCP connection logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); socket = new Socket(config.getServer(), config.getPort()); logger.info("Successfully connected to server."); - // Write login credentials - logger.finest("Sending login credentials..."); - SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); - // Create message receiver - Receiver receiver = new Receiver(socket.getInputStream()); + receiver = new Receiver(socket.getInputStream()); // Register user creation processor receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); + // Write login credentials + logger.finest("Sending login credentials..."); + SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); + // Start receiver new Thread(receiver).start(); @@ -66,6 +73,18 @@ public class Client { online = true; } + /** + * Sends a message to the server. + * + * @param message the message to send + * @throws IOException if the message does not reach the server + * @since Envoy v0.3-alpha + */ + public void sendMessage(Message message) throws IOException { + if (!online) throw new IllegalStateException("Client is not online"); + SerializationUtils.writeBytesWithLength(message, socket.getOutputStream()); + } + /** * @return a {@code Map} of all users on the server with their * user names as keys @@ -76,6 +95,9 @@ public class Client { return null; } + @Override + public void close() throws IOException { if (online) socket.close(); } + /** * @return the sender object that represents this client. * @since Envoy v0.1-alpha @@ -110,6 +132,11 @@ public class Client { */ public boolean hasRecipient() { return recipient != null; } + /** + * @return the {@link Receiver} used by this {@link Client} + */ + public Receiver getReceiver() { return receiver; } + /** * @return {@code true} if a connection to the server could be established * @since Envoy v0.2-alpha diff --git a/src/main/java/envoy/client/ObjectProcessor.java b/src/main/java/envoy/client/ObjectProcessor.java deleted file mode 100644 index b0aed2d..0000000 --- a/src/main/java/envoy/client/ObjectProcessor.java +++ /dev/null @@ -1,15 +0,0 @@ -package envoy.client; - - -/** - * Project: envoy-client
- * File: ObjectProcessor.java
- * Created: 30.12.2019
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha - */ -public interface ObjectProcessor { - - void process(T input); -} \ No newline at end of file diff --git a/src/main/java/envoy/client/Receiver.java b/src/main/java/envoy/client/Receiver.java index 64a4655..f70d6f9 100644 --- a/src/main/java/envoy/client/Receiver.java +++ b/src/main/java/envoy/client/Receiver.java @@ -4,6 +4,7 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; @@ -19,11 +20,16 @@ import envoy.client.util.EnvoyLog; */ public class Receiver implements Runnable { - private InputStream in; - private Map, ObjectProcessor> processors = new HashMap<>(); + private InputStream in; + private Map, Consumer> processors = new HashMap<>(); private static final Logger logger = EnvoyLog.getLogger(Receiver.class.getSimpleName()); + /** + * Creates an instance of {@link Receiver}. + * + * @param in the {@link InputStream} to parse objects from + */ public Receiver(InputStream in) { this.in = in; } @SuppressWarnings("unchecked") @@ -35,16 +41,23 @@ public class Receiver implements Runnable { logger.finest("Received object " + obj); // Get appropriate processor - ObjectProcessor processor = processors.get(obj.getClass()); + @SuppressWarnings("rawtypes") + Consumer processor = processors.get(obj.getClass()); if (processor == null) logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); - else - processor.process(obj); + else processor.accept(obj); } - } catch(Exception e) { + } catch (Exception e) { logger.log(Level.SEVERE, "Error on receiver thread", e); } } - public void registerProcessor(Class processorClass, ObjectProcessor processor) { processors.put(processorClass, processor); } + /** + * Adds an object processor to this {@link Receiver}. It will be called once an + * object of the accepted class has been received. + * + * @param processorClass the object class accepted by the processor + * @param processor the object processor + */ + public void registerProcessor(Class processorClass, Consumer processor) { processors.put(processorClass, processor); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 591be9f..b839c4c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -246,8 +246,13 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { - // Create and send message object + // Create message final Message message = new MessageBuilder(localDB.getUser(), currentChat.getRecipient()).setText(messageEnterTextArea.getText()).build(); + + // Send message + client.sendMessage(message); + + // Add message to LocalDB and update UI currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 1a2c96e..ae01e82 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -2,6 +2,7 @@ package envoy.client.ui; import java.awt.EventQueue; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -76,7 +77,7 @@ public class Startup { logger.severe("User name is not set or empty. Exiting..."); System.exit(1); } - + // TODO: create dialog String pass = JOptionPane.showInputDialog("Enter password"); @@ -125,17 +126,17 @@ public class Startup { // Initialize chats in local database try { localDB.initializeDBFile(); - // TODO: localDB.loadChats(); + localDB.loadChats(); + } catch (FileNotFoundException e) { + // The local database file has not yet been created, probably first login } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, - "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", + "Error while loading local database: " + e.toString() + "\nChats might not be stored locally.", "Local DB error", JOptionPane.WARNING_MESSAGE); } - logger.info("Client user ID: " + client.getSender().getId()); - // Save all users to the local database if (client.isOnline()) localDB.setUsers(client.getUsers()); @@ -147,8 +148,13 @@ public class Startup { try { new StatusTrayIcon(chatWindow).show(); - // If the tray icon is supported and corresponding settings is set, hide the chat window on close - Settings.getInstance().getItems().get("onCloseMode").setChangeHandler((onCloseMode) -> chatWindow.setDefaultCloseOperation((boolean) onCloseMode ? JFrame.HIDE_ON_CLOSE : JFrame.EXIT_ON_CLOSE)); + // If the tray icon is supported and corresponding settings is set, hide the + // chat window on close + Settings.getInstance() + .getItems() + .get("onCloseMode") + .setChangeHandler((onCloseMode) -> chatWindow + .setDefaultCloseOperation((boolean) onCloseMode ? JFrame.HIDE_ON_CLOSE : JFrame.EXIT_ON_CLOSE)); } catch (EnvoyException e) { logger.warning("The StatusTrayIcon is not supported on this platform!"); } @@ -160,13 +166,14 @@ public class Startup { // Save Settings and LocalDB on shutdown Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { - logger.info("Saving local database..."); + logger.info("Closing connection..."); + client.close(); + + logger.info("Saving local database and settings..."); localDB.save(); - logger.info("Saving settings..."); Settings.getInstance().save(); - } catch (IOException e1) { - e1.printStackTrace(); - logger.log(Level.WARNING, "Unable to save the messages", e1); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to save local files", e); } })); } From fde3ae2859cef9f86c14112d41f55a492d6030ed Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 31 Dec 2019 16:38:52 +0200 Subject: [PATCH 178/474] Acquiring user list through the sender object --- src/main/java/envoy/client/Client.java | 17 +++++++++++------ src/main/java/envoy/client/LocalDB.java | 4 ---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index b87f31d..37fc456 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -3,6 +3,7 @@ package envoy.client; import java.io.Closeable; import java.io.IOException; import java.net.Socket; +import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; @@ -56,13 +57,13 @@ public class Client implements Closeable { // Register user creation processor receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); + // Start receiver + new Thread(receiver).start(); + // Write login credentials logger.finest("Sending login credentials..."); SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); - // Start receiver - new Thread(receiver).start(); - // Wait for a maximum of five seconds to acquire the sender object long start = System.currentTimeMillis(); while (sender == null) { @@ -81,7 +82,7 @@ public class Client implements Closeable { * @since Envoy v0.3-alpha */ public void sendMessage(Message message) throws IOException { - if (!online) throw new IllegalStateException("Client is not online"); + checkOnline(); SerializationUtils.writeBytesWithLength(message, socket.getOutputStream()); } @@ -91,13 +92,17 @@ public class Client implements Closeable { * @since Envoy v0.2-alpha */ public Map getUsers() { - // TODO - return null; + checkOnline(); + Map users = new HashMap<>(); + sender.getContacts().forEach(u -> users.put(u.getName(), u)); + return users; } @Override public void close() throws IOException { if (online) socket.close(); } + private void checkOnline() { if (!online) throw new IllegalStateException("Client is not online"); } + /** * @return the sender object that represents this client. * @since Envoy v0.1-alpha diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index d550c3a..5bc5421 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -3,9 +3,7 @@ package envoy.client; import java.io.File; import java.io.IOException; import java.util.*; -import java.util.logging.Logger; -import envoy.client.util.EnvoyLog; import envoy.data.User; import envoy.util.SerializationUtils; @@ -25,8 +23,6 @@ public class LocalDB { private Map users = new HashMap<>(); private List chats = new ArrayList<>(); - private static final Logger logger = EnvoyLog.getLogger(LocalDB.class.getSimpleName()); - /** * Constructs an empty local database. To serialize any chats to the file * system, call {@link LocalDB#initializeDBFile()}. From 34785dc7f59b2e64a81d013320cd736805bee8aa Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 1 Jan 2020 18:18:18 +0200 Subject: [PATCH 179/474] Added LoginDialog --- .../java/envoy/client/ui/LoginDialog.java | 118 ++++++++++++++++++ src/main/java/envoy/client/ui/Startup.java | 22 ++-- 2 files changed, 128 insertions(+), 12 deletions(-) create mode 100644 src/main/java/envoy/client/ui/LoginDialog.java diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java new file mode 100644 index 0000000..db88176 --- /dev/null +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -0,0 +1,118 @@ +package envoy.client.ui; + +import java.awt.*; +import java.security.NoSuchAlgorithmException; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; + +import envoy.data.LoginCredentials; + +/** + * Project: envoy-client
+ * File: LoginDialog.java
+ * Created: 01.01.2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class LoginDialog extends JDialog { + + private final JPanel contentPanel = new JPanel(); + + private static final long serialVersionUID = 352021600833907468L; + private JTextField textField; + private JPasswordField passwordField; + + private LoginCredentials credentials; + + /** + * Displays a dialog enabling the user to enter their user name and password. + * + * @since Envoy v0.3-alpha + */ + public LoginDialog() { + setSize(338, 123); + setLocationRelativeTo(null); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + GridBagLayout gbl_contentPanel = new GridBagLayout(); + gbl_contentPanel.columnWidths = new int[] { 0, 0, 0 }; + gbl_contentPanel.rowHeights = new int[] { 0, 0, 0 }; + gbl_contentPanel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE }; + gbl_contentPanel.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE }; + contentPanel.setLayout(gbl_contentPanel); + { + JLabel lblUserName = new JLabel("User name:"); + GridBagConstraints gbc_lblUserName = new GridBagConstraints(); + gbc_lblUserName.anchor = GridBagConstraints.EAST; + gbc_lblUserName.insets = new Insets(0, 0, 5, 5); + gbc_lblUserName.gridx = 0; + gbc_lblUserName.gridy = 0; + contentPanel.add(lblUserName, gbc_lblUserName); + } + { + textField = new JTextField(); + GridBagConstraints gbc_textField = new GridBagConstraints(); + gbc_textField.insets = new Insets(0, 0, 5, 0); + gbc_textField.fill = GridBagConstraints.HORIZONTAL; + gbc_textField.gridx = 1; + gbc_textField.gridy = 0; + contentPanel.add(textField, gbc_textField); + textField.setColumns(10); + } + { + JLabel lblPassword = new JLabel("Password:"); + GridBagConstraints gbc_lblPassword = new GridBagConstraints(); + gbc_lblPassword.anchor = GridBagConstraints.EAST; + gbc_lblPassword.insets = new Insets(0, 0, 0, 5); + gbc_lblPassword.gridx = 0; + gbc_lblPassword.gridy = 1; + contentPanel.add(lblPassword, gbc_lblPassword); + } + { + passwordField = new JPasswordField(); + GridBagConstraints gbc_passwordField = new GridBagConstraints(); + gbc_passwordField.fill = GridBagConstraints.HORIZONTAL; + gbc_passwordField.gridx = 1; + gbc_passwordField.gridy = 1; + contentPanel.add(passwordField, gbc_passwordField); + } + { + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + { + JButton okButton = new JButton("OK"); + okButton.addActionListener((evt) -> { + try { + credentials = new LoginCredentials(textField.getText(), passwordField.getPassword()); + dispose(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + }); + okButton.setActionCommand("OK"); + buttonPane.add(okButton); + getRootPane().setDefaultButton(okButton); + } + { + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener((evt) -> dispose()); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton); + } + } + + setModal(true); + setVisible(true); + } + + /** + * @return the {@link LoginCredentials} entered by the user, or {@code null} if + * the dialog has been cancelled + * @since Envoy v0.3-alpha + */ + public LoginCredentials getCredentials() { return credentials; } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index ae01e82..3e4692d 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -71,15 +71,13 @@ public class Startup { EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); - // Ask the user for their user name - String userName = JOptionPane.showInputDialog("Please enter your username"); - if (userName == null || userName.isEmpty()) { - logger.severe("User name is not set or empty. Exiting..."); - System.exit(1); - } + // Ask the user for their user name and password + LoginCredentials credentials = new LoginDialog().getCredentials(); - // TODO: create dialog - String pass = JOptionPane.showInputDialog("Enter password"); + if (credentials == null) { + logger.info("The login process has been aborted by the user. Exiting..."); + System.exit(0); + } // Initialize the local database LocalDB localDB; @@ -99,18 +97,18 @@ public class Startup { Client client = new Client(); try { // Try entering online mode first - client.onlineInit(new LoginCredentials(userName, pass.toCharArray())); + client.onlineInit(credentials); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); e1.printStackTrace(); try { // Try entering offline mode localDB.loadUsers(); - User clientUser = localDB.getUsers().get(userName); + User clientUser = localDB.getUsers().get(credentials.getName()); if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); client.setSender(clientUser); JOptionPane.showMessageDialog(null, - "A connection to the server could not be established. Starting in offline mode.", + "A connection to the server could not be established. Starting in offline mode.\n" + e1, "Connection error", JOptionPane.WARNING_MESSAGE); } catch (Exception e2) { @@ -132,7 +130,7 @@ public class Startup { } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, - "Error while loading local database: " + e.toString() + "\nChats might not be stored locally.", + "Error while loading local database: " + e + "\nChats might not be stored locally.", "Local DB error", JOptionPane.WARNING_MESSAGE); } From 655ac58f3293ef6f6b6f79975bbe7a6d7aa8eed9 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 2 Jan 2020 17:11:41 +0200 Subject: [PATCH 180/474] Added contact initialization to handshake and ReceivedMessageProcessor --- src/main/java/envoy/client/Client.java | 29 +++- src/main/java/envoy/client/LocalDB.java | 160 ------------------ .../client/ReceivedMessageProcessor.java | 32 ++++ src/main/java/envoy/client/Receiver.java | 12 +- 4 files changed, 63 insertions(+), 170 deletions(-) create mode 100644 src/main/java/envoy/client/ReceivedMessageProcessor.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 37fc456..4885a92 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -7,11 +7,10 @@ import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; +import javax.naming.TimeLimitExceededException; + import envoy.client.util.EnvoyLog; -import envoy.data.LoginCredentials; -import envoy.data.Message; -import envoy.data.User; -import envoy.exception.EnvoyException; +import envoy.data.*; import envoy.util.SerializationUtils; /** @@ -33,12 +32,17 @@ public class Client implements Closeable { private volatile User sender; private User recipient; + private volatile Contacts contacts; + private Config config = Config.getInstance(); private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); /** - * Enters the online mode by acquiring a user ID from the server. + * Enters the online mode by acquiring a user ID from the server. As a + * connection has to be established and a handshake has to be made, this method + * will block for up to 5 seconds. If the handshake does exceed this time limit, + * an exception is thrown. * * @param credentials the login credentials of the user * @throws Exception if the online mode could not be entered or the request @@ -56,6 +60,7 @@ public class Client implements Closeable { // Register user creation processor receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); + receiver.registerProcessor(Contacts.class, contacts -> { logger.info("Acquired contacts object " + contacts); this.contacts = contacts; }); // Start receiver new Thread(receiver).start(); @@ -66,12 +71,19 @@ public class Client implements Closeable { // Wait for a maximum of five seconds to acquire the sender object long start = System.currentTimeMillis(); - while (sender == null) { - if (System.currentTimeMillis() - start > 5000) throw new EnvoyException("Did not log in after 5 seconds"); + while (sender == null || contacts == null) { + if (System.currentTimeMillis() - start > 5000) throw new TimeLimitExceededException("Did not log in after 5 seconds"); Thread.sleep(500); } + logger.info("Handshake completed."); online = true; + + // Remove user creation processor + receiver.removeAllProcessors(); + + // Register processors for message and status handling + receiver.registerProcessor(Message.class, new ReceivedMessageProcessor()); } /** @@ -84,6 +96,7 @@ public class Client implements Closeable { public void sendMessage(Message message) throws IOException { checkOnline(); SerializationUtils.writeBytesWithLength(message, socket.getOutputStream()); + message.nextStatus(); } /** @@ -94,7 +107,7 @@ public class Client implements Closeable { public Map getUsers() { checkOnline(); Map users = new HashMap<>(); - sender.getContacts().forEach(u -> users.put(u.getName(), u)); + contacts.getContacts().forEach(u -> users.put(u.getName(), u)); return users; } diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 5bc5421..2c40e65 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -84,166 +84,6 @@ public class LocalDB { */ public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } - // /** - // * Creates a {@link Sync} object filled with the changes that occurred to the - // * local database since the last synchronization. - // * - // * @param userId the ID of the user that is synchronized by this client - // * @return {@link Sync} object filled with the current changes - // * @since Envoy v0.1-alpha - // */ - // public Sync fillSync(long userId) { - // addWaitingMessagesToSync(); - // - // sync.getMessages().addAll(readMessages.getMessages()); - // readMessages.getMessages().clear(); - // - // logger.finest(String.format("Filled sync with %d messages.", - // sync.getMessages().size())); - // return sync; - // } - // - // /** - // * Applies the changes carried by a {@link Sync} object to the local database - // * - // * @param returnSync the {@link Sync} object to apply - // * @since Envoy v0.1-alpha - // */ - // public void applySync(Sync returnSync) { - // for (int i = 0; i < returnSync.getMessages().size(); i++) { - // - // // The message has an ID - // if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0) { - // - // // Messages are processes differently corresponding to their state - // switch (returnSync.getMessages().get(i).getMetadata().getState()) { - // case SENT: - // // Update previously waiting and now sent messages that were assigned an ID - // by - // // the server - // sync.getMessages().get(i).getMetadata().setMessageId(returnSync.getMessages().get(i).getMetadata().getMessageId()); - // sync.getMessages().get(i).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - // break; - // case RECEIVED: - // if (returnSync.getMessages().get(i).getMetadata().getSender() != 0) { - // // these are the unread Messages from the server - // unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); - // - // // Create and dispatch message creation event - // EventBus.getInstance().dispatch(new - // MessageCreationEvent(returnSync.getMessages().get(i))); - // } else { - // // Update Messages in localDB to state RECEIVED - // for (Chat chat : getChats()) - // if (chat.getRecipient().getId() == - // returnSync.getMessages().get(i).getMetadata().getRecipient()) - // for (int j = 0; j < chat.getModel().getSize(); j++) - // if (chat.getModel().get(j).getMetadata().getMessageId() == - // returnSync.getMessages() - // .get(i) - // .getMetadata() - // .getMessageId()) - // chat.getModel().get(j).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - // } - // break; - // case READ: - // // Update local Messages to state READ - // logger.info("Message with ID: " + - // returnSync.getMessages().get(i).getMetadata().getMessageId() - // + "was initialized to be set to READ in localDB."); - // for (Chat chat : getChats()) - // if (chat.getRecipient().getId() == - // returnSync.getMessages().get(i).getMetadata().getRecipient()) { - // logger.info("Chat with: " + chat.getRecipient().getId() + "was selected."); - // for (int k = 0; k < chat.getModel().getSize(); k++) - // if (chat.getModel().get(k).getMetadata().getMessageId() == - // returnSync.getMessages() - // .get(i) - // .getMetadata() - // .getMessageId()) { - // logger.info("Message with ID: " + - // chat.getModel().get(k).getMetadata().getMessageId() + "was selected."); - // chat.getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - // logger.info("Message State is now: " + - // chat.getModel().get(k).getMetadata().getState()); - // } - // } - // break; - // } - // } - // } - // - // // Updating UserStatus of all users in LocalDB - // for (User user : returnSync.getUsers()) - // for (Chat chat : getChats()) - // if (user.getId() == chat.getRecipient().getId()) - // chat.getRecipient().setStatus(user.getStatus()); - // - // sync.getMessages().clear(); - // sync.getUsers().clear(); - // } - // - // /** - // * Adds the unread messages returned from the server in the latest sync to the - // * right chats in the LocalDB. - // * - // * @since Envoy v0.1-alpha - // */ - // public void addUnreadMessagesToLocalDB() { - // for (Message message : unreadMessagesSync.getMessages()) - // for (Chat chat : getChats()) - // if (message.getMetadata().getSender() == chat.getRecipient().getId()) { - // chat.appendMessage(message); - // break; - // } - // } - // - // /** - // * Changes all messages with state {@code RECEIVED} of a specific chat to - // state - // * {@code READ}. - // *
- // * Adds these messages to the {@code readMessages} {@link Sync} object. - // * - // * @param currentChat the {@link Chat} that was just opened - // * @since Envoy v0.1-alpha - // */ - // public void setMessagesToRead(Chat currentChat) { - // for (int i = currentChat.getModel().size() - 1; i >= 0; --i) - // if (currentChat.getModel().get(i).getMetadata().getRecipient() != - // currentChat.getRecipient().getId()) - // if (currentChat.getModel().get(i).getMetadata().getState() == - // MessageState.RECEIVED) { - // currentChat.getModel().get(i).getMetadata().setState(MessageState.READ); - // readMessages.getMessages().add(currentChat.getModel().get(i)); - // } else break; - // } - // - // /** - // * Adds all messages with state {@code WAITING} from the {@link LocalDB} to - // the - // * {@link Sync} object. - // * - // * @since Envoy v0.1-alpha - // */ - // private void addWaitingMessagesToSync() { - // for (Chat chat : getChats()) - // for (int i = 0; i < chat.getModel().size(); i++) - // if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) - // { - // logger.info("Got Waiting Message"); - // sync.getMessages().add(chat.getModel().get(i)); - // } - // } - // - // /** - // * Clears the {@code unreadMessagesSync} {@link Sync} object. - // * - // * @since Envoy v0.1-alpha - // */ - // public void clearUnreadMessagesSync() { - // unreadMessagesSync.getMessages().clear(); } - /** * @return a {@code Map} of all users stored locally with their * user names as keys diff --git a/src/main/java/envoy/client/ReceivedMessageProcessor.java b/src/main/java/envoy/client/ReceivedMessageProcessor.java new file mode 100644 index 0000000..d408993 --- /dev/null +++ b/src/main/java/envoy/client/ReceivedMessageProcessor.java @@ -0,0 +1,32 @@ +package envoy.client; + +import java.util.function.Consumer; +import java.util.logging.Logger; + +import envoy.client.event.MessageCreationEvent; +import envoy.client.util.EnvoyLog; +import envoy.data.Message; +import envoy.data.Message.MessageStatus; +import envoy.event.EventBus; + +/** + * Project: envoy-client
+ * File: ReceivedMessageProcessor.java
+ * Created: 31.12.2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class ReceivedMessageProcessor implements Consumer { + + private static final Logger logger = EnvoyLog.getLogger(ReceivedMessageProcessor.class.getSimpleName()); + + @Override + public void accept(Message message) { + logger.info("Received message object " + message); + if (message.getStatus() != MessageStatus.SENT) logger.warning("The message has the unexpected status " + message.getStatus()); + else + // Dispatch event + EventBus.getInstance().dispatch(new MessageCreationEvent(message)); + } +} diff --git a/src/main/java/envoy/client/Receiver.java b/src/main/java/envoy/client/Receiver.java index f70d6f9..abe4687 100644 --- a/src/main/java/envoy/client/Receiver.java +++ b/src/main/java/envoy/client/Receiver.java @@ -2,6 +2,7 @@ package envoy.client; import java.io.InputStream; import java.io.ObjectInputStream; +import java.net.SocketException; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -20,8 +21,8 @@ import envoy.client.util.EnvoyLog; */ public class Receiver implements Runnable { - private InputStream in; - private Map, Consumer> processors = new HashMap<>(); + private final InputStream in; + private final Map, Consumer> processors = new HashMap<>(); private static final Logger logger = EnvoyLog.getLogger(Receiver.class.getSimpleName()); @@ -47,6 +48,8 @@ public class Receiver implements Runnable { logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); else processor.accept(obj); } + } catch (SocketException e) { + logger.info("Connection probably closed by client. Exiting receiver thread..."); } catch (Exception e) { logger.log(Level.SEVERE, "Error on receiver thread", e); } @@ -60,4 +63,9 @@ public class Receiver implements Runnable { * @param processor the object processor */ public void registerProcessor(Class processorClass, Consumer processor) { processors.put(processorClass, processor); } + + /** + * Removes all object processors registered at this {@link Receiver}. + */ + public void removeAllProcessors() { processors.clear(); } } \ No newline at end of file From 89be0d765f0122c288fa1fcd8b5df202e85a8797 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 3 Jan 2020 14:28:11 +0100 Subject: [PATCH 181/474] created bugfix pull request template --- .github/PULL_REQUEST_TEMPLATE/bugfix.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/bugfix.md diff --git a/.github/PULL_REQUEST_TEMPLATE/bugfix.md b/.github/PULL_REQUEST_TEMPLATE/bugfix.md new file mode 100644 index 0000000..e189f31 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/bugfix.md @@ -0,0 +1,10 @@ +--- +name: Bug fix +title: Fixed Bug +labels: bug +assignees: CyB3RC0nN0R, delvh, DieGurke +reviewers: CyB3RC0nN0R, delvh +projects: Envoy +milestone: Envoy v0.3-alpha +--- +Fixes #{issue} From b133d636df822a748a7c8151c4322b669d72b835 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 3 Jan 2020 14:31:22 +0100 Subject: [PATCH 182/474] created feature integration PRTemplate --- .github/PULL_REQUEST_TEMPLATE/feature_integration.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/feature_integration.md diff --git a/.github/PULL_REQUEST_TEMPLATE/feature_integration.md b/.github/PULL_REQUEST_TEMPLATE/feature_integration.md new file mode 100644 index 0000000..945e7d3 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/feature_integration.md @@ -0,0 +1,9 @@ +--- +name: Feature integration +title: Added feature +labels: enhancement +assignees: CyB3RC0nN0R, delvh, DieGurke +reviewers: CyB3RC0nN0R, delvh +projects: Envoy +milestone: Envoy v0.3-alpha +--- From f7ff49634baa08d3f79c958508829d623136ce8a Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 3 Jan 2020 14:36:16 +0100 Subject: [PATCH 183/474] Created Javadoc PRTemplate --- .github/PULL_REQUEST_TEMPLATE/javadoc_upgrade.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/javadoc_upgrade.md diff --git a/.github/PULL_REQUEST_TEMPLATE/javadoc_upgrade.md b/.github/PULL_REQUEST_TEMPLATE/javadoc_upgrade.md new file mode 100644 index 0000000..7f1786d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/javadoc_upgrade.md @@ -0,0 +1,9 @@ +--- +name: Updated Javadoc +title: Updated Javadoc +labels: documentation +assignees: CyB3RC0nN0R, delvh +reviewers: CyB3RC0nN0R, delvh +projects: Envoy +milestone: Envoy v0.3-alpha +--- From 4811decf5ec9bf34d252e845fde1dd42eb054324 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 3 Jan 2020 21:01:12 +0100 Subject: [PATCH 184/474] Update feature_request.md --- .github/ISSUE_TEMPLATE/feature_request.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index fbdebf6..8341438 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,8 +2,10 @@ name: Feature request about: Suggest an idea for this project title: '' -labels: enhancement +labels: enhancement, feature assignees: CyB3RC0nN0R, delvh, DieGurke +project: Envoy +milestones: Envoy v0.3-alpha --- From 98728e84596fda378b4cd0426957cb50ce20a768 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 3 Jan 2020 21:27:49 +0100 Subject: [PATCH 185/474] Create CONTRIBUTING.md --- CONTRIBUTING.md | 161 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1d682be --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,161 @@ +# Contributing to Envoy + +Looking to contribute something to Envoy? **Here's how you can help.** + +Please take a moment to review this document in order to make the contribution +process easy and effective for everyone involved. + +Following these guidelines helps to communicate that you respect the time of +the developers managing and developing this open source project. In return, +they should reciprocate that respect in addressing your issue or assessing +patches and features. + + +## Using the issue tracker + +The [issue tracker](https://github.com/informatik-ag-ngl/envoy-client/issues) is +the preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests) +and [submitting pull requests](#pull-requests), but please respect the following +restrictions: + +* Please **do not** derail or troll issues. Keep the discussion on topic and + respect the opinions of others. + +* Please **do not** post comments consisting solely of "+1" or ":thumbsup:". + Use [GitHub's "reactions" feature](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) + instead. We reserve the right to delete comments which violate this rule. + + However, as we know, we are all software engineers that like being funny hence doing it on purpose. Please also refrain from that kind of behaviour. + +## Issues and labels + +Our bug tracker utilizes several labels to help organize and identify issues. Here's what they represent and how we use them: + +- `Documentation` & `Javadoc`- Issues regarding the documentation of Envoy +- `Enhancement` & `Feature` - Issues suggesting a new feature +- `Maven` - Issues concerned with Maven problems +- `Bug` - Issues concerned with a general bug + +For a complete look at our labels, see the [project labels page](https://github.com/informatik-ag-ngl/envoy-client/labels). + +## Bug reports + +A bug is a _demonstrable problem_ that is caused by the code in the repository. +Good bug reports are extremely helpful, so thanks! + +Guidelines for bug reports: + +0. **ensure your problem isn't caused by a simple error in your own code**. + +1. **Use the GitHub issue search** — check if the issue has already been + reported. + +2. **Check if the issue has been fixed** — try to reproduce it using the + latest `master` or development branch in the repository. + +3. **Isolate the problem** — ideally create a reduced test + case and a live example. + + +A good bug report shouldn't leave others needing to chase you up for more +information. Please try to be as detailed as possible in your report. What is +your environment? What steps will reproduce the issue? These details will help people to fix +any potential bugs. + +Example: + +> Short and descriptive example bug report title +> +> 1. This is the first step +> 2. This is the second step +> 3. Further steps, etc. +> +> Any other information you want to share that is relevant to the issue being +> reported. This might include the lines of code that you have identified as +> causing the bug, and potential solutions (and your opinions on their +> merits). + +## Feature requests + +Feature requests are welcome. But take a moment to find out whether your idea +fits with the scope and aims of the project. It's up to *you* to make a strong +case to convince the project's developers of the merits of this feature. Please +provide as much detail and context as possible. + + +## Pull requests + +Good pull requests—patches, improvements, new features—are a fantastic +help. They should remain focused in scope and avoid containing unrelated +commits. + +**Please ask first** before embarking on any significant pull request (e.g. +implementing features, refactoring code, porting to a different language), +otherwise you risk spending a lot of time working on something that the +project's developers might not want to merge into the project. + +Please adhere to the [coding guidelines](#code-guidelines) used throughout the +project (indentation, accurate comments, etc.) and any other requirements +(such as test coverage). + +Adhering to the following process is the best way to get your work +included in the project: + +1. Download, clone or [Fork](https://help.github.com/articles/fork-a-repo/) the project, using [https://github.com/informatik-ag-ngl/envoy-client/](https://github.com/informatik-ag-ngl/envoy-client/)as Remote. + +2. If you cloned a while ago, get the latest changes from upstream: + + ```bash + git checkout master + git pull upstream master + ``` + Or, if your IDE of choice supports this, simply use `pull` + +3. Create a new topic branch (off the main project development branch) to + contain your feature, change, or fix: + + ```bash + git checkout -b + ``` + Or, simply use "New branch" if your IDE supports this + +4. Commit your changes in logical chunks. Please adhere to these [git commit + message guidelines](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) + or your code is unlikely be merged into the main project. Use Git's + [interactive rebase](https://help.github.com/articles/about-git-rebase/) + feature to tidy up your commits before making them public. + +5. Locally merge (or rebase) the upstream development branch into your topic branch: + + ```bash + git pull [--rebase] upstream master + ``` + +6. Push your topic branch up to your fork: + + ```bash + git push origin + ``` + +7. [Open a Pull Request](https://help.github.com/articles/about-pull-requests/) + with a clear title and description against the `master` branch. + +**IMPORTANT**: By submitting a patch, you agree to allow the project owners to +license your work under the terms of the [MIT License](../LICENSE) (if it +includes code changes) and under the terms of the +[Creative Commons Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/) +(if it includes documentation changes). + + +## Code guidelines + +### Java + +Please use the formatter provided with this project. Especially before saving. For best results, select the option "format code" in the "Save Actions" tab in Preferences in Eclipse, so that you never accidentally forget it. +Every public function (not annotated with `@Override`) must be delivered with Javadoc. For best project-appropriate Javadoc please take a look at the other functions which are all already equipped with Javadoc. + + +## License + +By contributing your code, you agree to license your contribution under the [MIT License](../LICENSE). +By contributing to the documentation, you agree to license your contribution under the [Creative Commons Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/). From d005bcd4c976eaf4d4aff48a8297bb2e53383fb8 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 6 Jan 2020 15:00:44 +0200 Subject: [PATCH 186/474] Adjusted message creation to the updated MessageBuilder. --- src/main/java/envoy/client/ui/ChatWindow.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index b839c4c..4f8b0dc 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -247,7 +247,9 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { // Create message - final Message message = new MessageBuilder(localDB.getUser(), currentChat.getRecipient()).setText(messageEnterTextArea.getText()).build(); + final Message message = new MessageBuilder(localDB.getUser().getId(), currentChat.getRecipient().getId()) + .setText(messageEnterTextArea.getText()) + .build(); // Send message client.sendMessage(message); From 80fc11f91e5a922b550ef9ed1ff340fb65cf0ded Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 6 Jan 2020 17:37:38 +0100 Subject: [PATCH 187/474] Fixed ObjectInputStream header error by reading chunks. --- .classpath | 6 ---- src/main/java/envoy/client/Receiver.java | 39 ++++++++++++++++-------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/.classpath b/.classpath index 1a0c560..a5d9509 100644 --- a/.classpath +++ b/.classpath @@ -28,11 +28,5 @@ - - - - - - diff --git a/src/main/java/envoy/client/Receiver.java b/src/main/java/envoy/client/Receiver.java index abe4687..e6cd3c5 100644 --- a/src/main/java/envoy/client/Receiver.java +++ b/src/main/java/envoy/client/Receiver.java @@ -1,5 +1,6 @@ package envoy.client; +import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.ObjectInputStream; import java.net.SocketException; @@ -10,12 +11,13 @@ import java.util.logging.Level; import java.util.logging.Logger; import envoy.client.util.EnvoyLog; +import envoy.util.SerializationUtils; /** * Project: envoy-client
* File: Receiver.java
* Created: 30.12.2019
- * + * * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ @@ -36,29 +38,42 @@ public class Receiver implements Runnable { @SuppressWarnings("unchecked") @Override public void run() { - try (ObjectInputStream oin = new ObjectInputStream(in)) { - while (true) { - Object obj = oin.readObject(); - logger.finest("Received object " + obj); - // Get appropriate processor - @SuppressWarnings("rawtypes") - Consumer processor = processors.get(obj.getClass()); - if (processor == null) - logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); - else processor.accept(obj); + try { + while (true) { + // Read object length + byte[] lenBytes = new byte[4]; + in.read(lenBytes); + int len = SerializationUtils.bytesToInt(lenBytes, 0); + + // Read object into byte array + byte[] objBytes = new byte[len]; + in.read(objBytes); + + try (ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(objBytes))) { + Object obj = oin.readObject(); + logger.finest("Received object " + obj); + + // Get appropriate processor + @SuppressWarnings("rawtypes") + Consumer processor = processors.get(obj.getClass()); + if (processor == null) + logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); + else processor.accept(obj); + } } } catch (SocketException e) { logger.info("Connection probably closed by client. Exiting receiver thread..."); } catch (Exception e) { logger.log(Level.SEVERE, "Error on receiver thread", e); + e.printStackTrace(); } } /** * Adds an object processor to this {@link Receiver}. It will be called once an * object of the accepted class has been received. - * + * * @param processorClass the object class accepted by the processor * @param processor the object processor */ From 1eadb8517392b44d054546df5ef10629ee8dabbb Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 6 Jan 2020 18:13:00 +0100 Subject: [PATCH 188/474] Moved MessageEvent back from envoy-common. --- .../client/event/MessageCreationEvent.java | 1 - .../java/envoy/client/event/MessageEvent.java | 31 +++++++++++++++++++ .../event/MessageModificationEvent.java | 1 - 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/main/java/envoy/client/event/MessageEvent.java diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java index d2e372d..36397d9 100644 --- a/src/main/java/envoy/client/event/MessageCreationEvent.java +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -1,7 +1,6 @@ package envoy.client.event; import envoy.data.Message; -import envoy.event.MessageEvent; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java new file mode 100644 index 0000000..a1b5c68 --- /dev/null +++ b/src/main/java/envoy/client/event/MessageEvent.java @@ -0,0 +1,31 @@ +package envoy.client.event; + +import envoy.data.Message; +import envoy.event.Event; + +/** + * Project: envoy-client
+ * File: MessageCreationEvent.java
+ * Created: 4 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class MessageEvent implements Event { + + /** + * the {@link Message} attached to this {@link MessageEvent}. + */ + protected final Message message; + + /** + * Initializes a {@link MessageEvent} conveying information about a + * {@link Message} object. + * + * @param message the {@link Message} object to attach to this event + * @since Envoy v0.2-alpha + */ + public MessageEvent(Message message) { this.message = message; } + + @Override + public Message get() { return message; } +} diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java index a5b7c41..248c6f1 100644 --- a/src/main/java/envoy/client/event/MessageModificationEvent.java +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -1,7 +1,6 @@ package envoy.client.event; import envoy.data.Message; -import envoy.event.MessageEvent; /** * Project: envoy-client
From 98f3db0c99a44fe31b54a005efc0166d690079bd Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 11 Jan 2020 11:46:20 +0100 Subject: [PATCH 189/474] Replaced local dependency by jitpack.io dependency --- pom.xml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 28e6f60..ecf4beb 100644 --- a/pom.xml +++ b/pom.xml @@ -17,11 +17,18 @@ 1.8 + + + jitpack.io + https://jitpack.io + + + - informatik-ag-ngl + com.github.informatik-ag-ngl envoy-common - 0.2-alpha + develop-SNAPSHOT From 34df965cdbf2465fbccc7cee4e8e6b782c87d91b Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 11 Jan 2020 11:58:15 +0100 Subject: [PATCH 190/474] Added maven build action --- .github/workflows/maven.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..91106d3 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,17 @@ +name: Java CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Build with Maven + run: mvn -B package --file pom.xml From cd925bf0c9a96aa0115cd1a6348434699d8ca541 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 18 Jan 2020 10:34:04 +0100 Subject: [PATCH 191/474] Prepared user registration implementation --- .classpath | 6 ++++++ pom.xml | 2 +- src/main/java/envoy/client/ui/LoginDialog.java | 2 +- src/main/java/envoy/client/ui/MessageListRenderer.java | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.classpath b/.classpath index a5d9509..1a0c560 100644 --- a/.classpath +++ b/.classpath @@ -28,5 +28,11 @@
+ + + + + + diff --git a/pom.xml b/pom.xml index ecf4beb..01fa149 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - develop-SNAPSHOT + e5c67b8 diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index db88176..d8a3c9d 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -87,7 +87,7 @@ public class LoginDialog extends JDialog { JButton okButton = new JButton("OK"); okButton.addActionListener((evt) -> { try { - credentials = new LoginCredentials(textField.getText(), passwordField.getPassword()); + credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); dispose(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 33f36f9..ed62854 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -41,7 +41,7 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer Date: Sat, 18 Jan 2020 13:13:03 +0100 Subject: [PATCH 192/474] Registration UI --- .../java/envoy/client/ui/LoginDialog.java | 75 ++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index d8a3c9d..d81ecc1 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -1,7 +1,10 @@ package envoy.client.ui; import java.awt.*; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.security.NoSuchAlgorithmException; +import java.util.Arrays; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -14,6 +17,7 @@ import envoy.data.LoginCredentials; * Created: 01.01.2020
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy v0.3-alpha */ public class LoginDialog extends JDialog { @@ -24,6 +28,11 @@ public class LoginDialog extends JDialog { private JTextField textField; private JPasswordField passwordField; + private JPasswordField repeatPasswordField; + private JLabel lblRepeatPassword; + private GridBagConstraints gbc_lblRepeatPassword; + private GridBagConstraints gbc_repeatPasswordField; + private LoginCredentials credentials; /** @@ -79,16 +88,78 @@ public class LoginDialog extends JDialog { gbc_passwordField.gridy = 1; contentPanel.add(passwordField, gbc_passwordField); } + { + lblRepeatPassword = new JLabel("Repeat Password:"); + gbc_lblRepeatPassword = new GridBagConstraints(); + gbc_lblRepeatPassword.anchor = GridBagConstraints.EAST; + gbc_lblRepeatPassword.insets = new Insets(0, 0, 0, 5); + gbc_lblRepeatPassword.gridx = 0; + gbc_lblRepeatPassword.gridy = 2; + } + { + repeatPasswordField = new JPasswordField(); + gbc_repeatPasswordField = new GridBagConstraints(); + gbc_repeatPasswordField.fill = GridBagConstraints.HORIZONTAL; + gbc_repeatPasswordField.gridx = 1; + gbc_repeatPasswordField.gridy = 2; + } { JPanel buttonPane = new JPanel(); + + JTextPane registerText = new JTextPane(); + registerText.setText("Register?"); + registerText.setFont(new Font("Arial", Font.BOLD, 12)); + registerText.setAlignmentX(LEFT_ALIGNMENT); + buttonPane.add(registerText); + + JCheckBox registerCheckBox = new JCheckBox(); + registerCheckBox.setAlignmentX(LEFT_ALIGNMENT); + registerCheckBox.addItemListener(new ItemListener() { + + @Override + public void itemStateChanged(ItemEvent e) { + switch (e.getStateChange()) { + case ItemEvent.SELECTED: + contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword); + contentPanel.add(repeatPasswordField, gbc_repeatPasswordField); + setSize(338, 160); + contentPanel.revalidate(); + contentPanel.repaint(); + break; + + case ItemEvent.DESELECTED: + if (repeatPasswordField.getParent() == contentPanel) { + contentPanel.remove(lblRepeatPassword); + contentPanel.remove(repeatPasswordField); + setSize(338, 123); + contentPanel.revalidate(); + contentPanel.repaint(); + } + break; + } + } + }); + buttonPane.add(registerCheckBox); + buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); getContentPane().add(buttonPane, BorderLayout.SOUTH); { JButton okButton = new JButton("OK"); okButton.addActionListener((evt) -> { try { - credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); - dispose(); + if (registerCheckBox.isSelected()) { + if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) { + credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), true); + dispose(); + } else { + JOptionPane.showMessageDialog(this, "The repeated password is unequal to the origional password!"); + passwordField.setText(null); + repeatPasswordField.setText(null); + } + } else { + credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); + dispose(); + } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } From 2f4583861eeef8b0cfd671e8f2ef02861ddf6118 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 25 Jan 2020 11:33:28 +0100 Subject: [PATCH 193/474] Added component list classes (unfinished) --- .../envoy/client/ui/list/ComponentList.java | 32 +++++++ .../ui/list/ComponentListCellRenderer.java | 16 ++++ .../client/ui/list/ComponentListModel.java | 83 +++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 src/main/java/envoy/client/ui/list/ComponentList.java create mode 100644 src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java create mode 100644 src/main/java/envoy/client/ui/list/ComponentListModel.java diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java new file mode 100644 index 0000000..869721c --- /dev/null +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -0,0 +1,32 @@ +package envoy.client.ui.list; + +import javax.swing.BoxLayout; +import javax.swing.JPanel; + +/** + * Project: envoy-client
+ * File: ComponentList.java
+ * Created: 25.01.2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class ComponentList extends JPanel { + + private ComponentListCellRenderer renderer; + + private static final long serialVersionUID = 1759644503942876737L; + + public ComponentList(ComponentListModel model, ComponentListCellRenderer renderer) { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + model.setComponentList(this); + this.renderer = renderer; + + for (E elem : model) + add(renderer.getListCellComponent(this, elem, false)); + } + + void add(E elem) { + add(renderer.getListCellComponent(this, elem, false)); + } +} diff --git a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java b/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java new file mode 100644 index 0000000..6a3b383 --- /dev/null +++ b/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java @@ -0,0 +1,16 @@ +package envoy.client.ui.list; + +import java.awt.Component; + +/** + * Project: envoy-client
+ * File: ComponentListCellRenderer.java
+ * Created: 25.01.2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public interface ComponentListCellRenderer { + + Component getListCellComponent(ComponentList list, E value, boolean isSelected); +} diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java new file mode 100644 index 0000000..e5ea6fe --- /dev/null +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -0,0 +1,83 @@ +package envoy.client.ui.list; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Project: envoy-client
+ * File: ComponentListModel.java
+ * Created: 25.01.2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public final class ComponentListModel implements Iterable { + + private List elements = new ArrayList<>(); + private ComponentList componentList; + + /** + * Adds an element to this model and notifies the associated + * {@link ComponentList} to add the corresponding component. + * + * @param e the element to add + * @return {@code true} + * @see java.util.List#add(java.lang.Object) + */ + public boolean add(E e) { + componentList.add(e); + return elements.add(e); + } + + /** + * Removes all elements from this model and clears the associated + * {@link ComponentList}. + * + * @see java.util.List#clear() + * @since Envoy v0.3-alpha + */ + public void clear() { + elements.clear(); + componentList.removeAll(); + } + + /** + * @param index + * @return + * @see java.util.List#get(int) + */ + public E get(int index) { return elements.get(index); } + + /** + * Removes the element at a specific index from this model and the corresponding + * component from the {@link ComponentList}. + * + * @param index + * @return the removed element + * @see java.util.List#remove(int) + */ + public E remove(int index) { + componentList.remove(index); + return elements.remove(index); + } + + /** + * @return + * @see java.util.List#iterator() + */ + public Iterator iterator() { + return new Iterator() { + + Iterator iter = elements.iterator(); + + @Override + public boolean hasNext() { return iter.hasNext(); } + + @Override + public E next() { return iter.next(); } + }; + } + + void setComponentList(ComponentList componentList) { this.componentList = componentList; } +} From 7dfe68eebbb2a859c31198056604e8106cb11cc1 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 26 Jan 2020 22:10:15 +0100 Subject: [PATCH 194/474] Started ComponentList integration for message list --- src/main/java/envoy/client/Chat.java | 9 +++---- src/main/java/envoy/client/ui/ChatWindow.java | 26 +++++++++---------- .../envoy/client/ui/MessageListRenderer.java | 14 +++++----- .../envoy/client/ui/list/ComponentList.java | 24 ++++++++++++++--- .../ui/list/ComponentListCellRenderer.java | 2 +- .../client/ui/list/ComponentListModel.java | 17 +++++++----- 6 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index ef762c4..20513e4 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -2,8 +2,7 @@ package envoy.client; import java.io.Serializable; -import javax.swing.DefaultListModel; - +import envoy.client.ui.list.ComponentListModel; import envoy.data.Message; import envoy.data.User; @@ -25,7 +24,7 @@ public class Chat implements Serializable { private static final long serialVersionUID = -7751248474547242056L; private User recipient; - private DefaultListModel model = new DefaultListModel<>(); + private ComponentListModel model = new ComponentListModel<>(); /** * Provides the list of messages that the recipient receives.
@@ -48,11 +47,11 @@ public class Chat implements Serializable { * @param message the message to add in said chat * @since Envoy v0.1-alpha */ - public void appendMessage(Message message) { model.addElement(message); } + public void appendMessage(Message message) { model.add(message); } /** * @return all messages in the current chat * @since Envoy v0.1-alpha */ - public DefaultListModel getModel() { return model; } + public ComponentListModel getModel() { return model; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 4f8b0dc..671deda 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -11,6 +11,8 @@ import javax.swing.border.EmptyBorder; import envoy.client.*; import envoy.client.event.ThemeChangeEvent; +import envoy.client.ui.list.ComponentList; +import envoy.client.ui.list.ComponentListModel; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; import envoy.data.Message; @@ -41,7 +43,7 @@ public class ChatWindow extends JFrame { private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); private JList userList = new JList<>(); private Chat currentChat; - private JList messageList = new JList<>(); + private ComponentList messageList; private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); private JTextPane textPane = new JTextPane(); private PrimaryButton postButton = new PrimaryButton("Post"); @@ -73,14 +75,12 @@ public class ChatWindow extends JFrame { gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 }; contentPane.setLayout(gbl_contentPane); - messageList.setCellRenderer(new MessageListRenderer()); - messageList.setFocusTraversalKeysEnabled(false); - messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + messageList = new ComponentList<>(new ComponentListModel<>(), new MessageListRenderer()); + // TODO: messageList.setFocusTraversalKeysEnabled(false); + // messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); - DefaultListModel messageListModel = new DefaultListModel<>(); - messageList.setModel(messageListModel); - messageList.setFont(new Font("Arial", Font.PLAIN, 17)); - messageList.setFixedCellHeight(60); + // messageList.setFont(new Font("Arial", Font.PLAIN, 17)); + // messageList.setFixedCellHeight(60); messageList.setBorder(new EmptyBorder(space, space, space, space)); scrollPane.setViewportView(messageList); @@ -101,7 +101,7 @@ public class ChatWindow extends JFrame { public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) - postMessage(messageList); + postMessage(); } }); @@ -123,7 +123,7 @@ public class ChatWindow extends JFrame { gbc_moveSelectionPostButton.insets = new Insets(space, space, space, space); - postButton.addActionListener((evt) -> { postMessage(messageList); }); + postButton.addActionListener((evt) -> { postMessage(); }); contentPane.add(postButton, gbc_moveSelectionPostButton); // Settings Button @@ -210,8 +210,8 @@ public class ChatWindow extends JFrame { contentPane.setBackground(theme.getBackgroundColor()); contentPane.setForeground(theme.getUserNameColor()); // messageList - messageList.setSelectionForeground(theme.getUserNameColor()); - messageList.setSelectionBackground(theme.getSelectionColor()); + // messageList.setSelectionForeground(theme.getUserNameColor()); + // messageList.setSelectionBackground(theme.getSelectionColor()); messageList.setForeground(theme.getMessageColorChat()); messageList.setBackground(theme.getCellColor()); // scrollPane @@ -238,7 +238,7 @@ public class ChatWindow extends JFrame { userList.setBackground(theme.getCellColor()); } - private void postMessage(JList messageList) { + private void postMessage() { if (!client.hasRecipient()) { JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); return; diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index ed62854..c3bebac 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -4,10 +4,10 @@ import java.awt.Component; import java.text.SimpleDateFormat; import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.ListCellRenderer; import envoy.client.Settings; +import envoy.client.ui.list.ComponentList; +import envoy.client.ui.list.ComponentListCellRenderer; import envoy.data.Message; /** @@ -21,15 +21,17 @@ import envoy.data.Message; * @author Maximilian Käfer * @since Envoy v0.1-alpha */ -public class MessageListRenderer extends JLabel implements ListCellRenderer { +public class MessageListRenderer extends JLabel implements ComponentListCellRenderer { private static final long serialVersionUID = 5164417379767181198L; @Override - public Component getListCellRendererComponent(JList list, Message value, int index, boolean isSelected, boolean cellHasFocus) { + public Component getListCellComponent(ComponentList list, Message value, boolean isSelected) { if (isSelected) { - setBackground(list.getSelectionBackground()); - setForeground(list.getSelectionForeground()); + setBackground(Color.DARK_GRAY); + setForeground(Color.RED); +// setBackground(list.getSelectionBackground()); +// setForeground(list.getSelectionForeground()); } else { setBackground(list.getBackground()); setForeground(list.getForeground()); diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 869721c..313838d 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -13,20 +13,36 @@ import javax.swing.JPanel; */ public class ComponentList extends JPanel { + private ComponentListModel model; private ComponentListCellRenderer renderer; private static final long serialVersionUID = 1759644503942876737L; public ComponentList(ComponentListModel model, ComponentListCellRenderer renderer) { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - model.setComponentList(this); - this.renderer = renderer; + this.model = model; + this.renderer = renderer; + setModel(model); + } - for (E elem : model) - add(renderer.getListCellComponent(this, elem, false)); + public void setModel(ComponentListModel model) { + // Remove old model + this.model.clear(); + this.model.setComponentList(null); + + // Synchronize with new model + this.model = model; + this.model.setComponentList(this); + synchronizeModel(); } void add(E elem) { add(renderer.getListCellComponent(this, elem, false)); } + + private void synchronizeModel() { + removeAll(); + for (E elem : model) + add(renderer.getListCellComponent(this, elem, false)); + } } diff --git a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java b/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java index 6a3b383..95d196d 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java +++ b/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java @@ -12,5 +12,5 @@ import java.awt.Component; */ public interface ComponentListCellRenderer { - Component getListCellComponent(ComponentList list, E value, boolean isSelected); + Component getListCellComponent(ComponentList list, E value, boolean isSelected); } diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java index e5ea6fe..27db590 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -14,8 +14,8 @@ import java.util.List; */ public final class ComponentListModel implements Iterable { - private List elements = new ArrayList<>(); - private ComponentList componentList; + private List elements = new ArrayList<>(); + private ComponentList componentList; /** * Adds an element to this model and notifies the associated @@ -26,7 +26,7 @@ public final class ComponentListModel implements Iterable { * @see java.util.List#add(java.lang.Object) */ public boolean add(E e) { - componentList.add(e); + if (componentList != null) componentList.add(e); return elements.add(e); } @@ -39,7 +39,7 @@ public final class ComponentListModel implements Iterable { */ public void clear() { elements.clear(); - componentList.removeAll(); + if (componentList != null) componentList.removeAll(); } /** @@ -58,7 +58,7 @@ public final class ComponentListModel implements Iterable { * @see java.util.List#remove(int) */ public E remove(int index) { - componentList.remove(index); + if (componentList != null) componentList.remove(index); return elements.remove(index); } @@ -70,7 +70,7 @@ public final class ComponentListModel implements Iterable { return new Iterator() { Iterator iter = elements.iterator(); - + @Override public boolean hasNext() { return iter.hasNext(); } @@ -79,5 +79,8 @@ public final class ComponentListModel implements Iterable { }; } - void setComponentList(ComponentList componentList) { this.componentList = componentList; } + void setComponentList(ComponentList componentList) { + this.componentList = componentList; + if (componentList != null) elements.forEach(componentList::add); + } } From 05304ecca9e1162ebbbb14f5efa454026a1b0526 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 27 Jan 2020 07:06:38 +0100 Subject: [PATCH 195/474] Removed src/test/resources folder --- .classpath | 6 ------ pom.xml | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.classpath b/.classpath index 1a0c560..a5d9509 100644 --- a/.classpath +++ b/.classpath @@ -28,11 +28,5 @@
- - - - - - diff --git a/pom.xml b/pom.xml index 01fa149..bf35cbb 100644 --- a/pom.xml +++ b/pom.xml @@ -34,5 +34,10 @@ envoy-client + + + src/main/resources + + \ No newline at end of file From 37a54303d34c8a275c3aa679bff56cee44a721d5 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 27 Jan 2020 20:11:47 +0100 Subject: [PATCH 196/474] Implemented ComponentList rendering and integration of message list --- src/main/java/envoy/client/ui/ChatWindow.java | 51 ++++++++++--------- .../envoy/client/ui/MessageListRenderer.java | 32 +++++++----- .../envoy/client/ui/list/ComponentList.java | 27 ++++++---- .../ui/list/ComponentListCellRenderer.java | 6 +-- .../client/ui/list/ComponentListModel.java | 20 +++++--- 5 files changed, 77 insertions(+), 59 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 671deda..3c4cdee 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -12,7 +12,6 @@ import javax.swing.border.EmptyBorder; import envoy.client.*; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.list.ComponentList; -import envoy.client.ui.list.ComponentListModel; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; import envoy.data.Message; @@ -32,27 +31,29 @@ import envoy.event.EventBus; */ public class ChatWindow extends JFrame { - private static final long serialVersionUID = 6865098428255463649L; - // User specific objects private Client client; private LocalDB localDB; // GUI components - private JPanel contentPane = new JPanel(); - private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); - private JList userList = new JList<>(); - private Chat currentChat; - private ComponentList messageList; - private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); - private JTextPane textPane = new JTextPane(); - private PrimaryButton postButton = new PrimaryButton("Post"); - private PrimaryButton settingsButton = new PrimaryButton("Settings"); - - private static int space = 4; + private JPanel contentPane = new JPanel(); + private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); + private JList userList = new JList<>(); + private Chat currentChat; + private ComponentList messageList = new ComponentList<>(new MessageListRenderer()); + private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); + private JTextPane textPane = new JTextPane(); + private PrimaryButton postButton = new PrimaryButton("Post"); + private PrimaryButton settingsButton = new PrimaryButton("Settings"); private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class.getSimpleName()); + // GUI component spacing + private final static int space = 4; + private static final Insets insets = new Insets(space, space, space, space); + + private static final long serialVersionUID = 6865098428255463649L; + /** * Initializes a {@link JFrame} with UI elements used to send and read messages * to different users. @@ -75,7 +76,6 @@ public class ChatWindow extends JFrame { gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 }; contentPane.setLayout(gbl_contentPane); - messageList = new ComponentList<>(new ComponentListModel<>(), new MessageListRenderer()); // TODO: messageList.setFocusTraversalKeysEnabled(false); // messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); @@ -91,7 +91,7 @@ public class ChatWindow extends JFrame { gbc_scrollPane.gridx = 1; gbc_scrollPane.gridy = 1; - gbc_scrollPane.insets = new Insets(space, space, space, space); + gbc_scrollPane.insets = insets; contentPane.add(scrollPane, gbc_scrollPane); // Message enter field @@ -100,7 +100,7 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER - && ((Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) + && (Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0 || e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK)) postMessage(); } }); @@ -110,7 +110,7 @@ public class ChatWindow extends JFrame { gbc_messageEnterTextfield.gridx = 1; gbc_messageEnterTextfield.gridy = 2; - gbc_messageEnterTextfield.insets = new Insets(space, space, space, space); + gbc_messageEnterTextfield.insets = insets; contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); @@ -121,7 +121,7 @@ public class ChatWindow extends JFrame { gbc_moveSelectionPostButton.gridx = 2; gbc_moveSelectionPostButton.gridy = 2; - gbc_moveSelectionPostButton.insets = new Insets(space, space, space, space); + gbc_moveSelectionPostButton.insets = insets; postButton.addActionListener((evt) -> { postMessage(); }); contentPane.add(postButton, gbc_moveSelectionPostButton); @@ -133,7 +133,7 @@ public class ChatWindow extends JFrame { gbc_moveSelectionSettingsButton.gridx = 2; gbc_moveSelectionSettingsButton.gridy = 0; - gbc_moveSelectionSettingsButton.insets = new Insets(space, space, space, space); + gbc_moveSelectionSettingsButton.insets = insets; settingsButton.addActionListener((evt) -> { try { @@ -154,7 +154,7 @@ public class ChatWindow extends JFrame { gbc_partnerName.gridx = 1; gbc_partnerName.gridy = 0; - gbc_partnerName.insets = new Insets(space, space, space, space); + gbc_partnerName.insets = insets; contentPane.add(textPane, gbc_partnerName); userList.setCellRenderer(new UserListRenderer()); @@ -187,7 +187,7 @@ public class ChatWindow extends JFrame { gbc_userList.gridx = 0; gbc_userList.gridy = 1; gbc_userList.anchor = GridBagConstraints.PAGE_START; - gbc_userList.insets = new Insets(space, space, space, space); + gbc_userList.insets = insets; applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); @@ -252,15 +252,18 @@ public class ChatWindow extends JFrame { .build(); // Send message + // TODO: Store offline messages client.sendMessage(message); // Add message to LocalDB and update UI currentChat.appendMessage(message); - messageList.setModel(currentChat.getModel()); + // messageList.setModel(currentChat.getModel()); // Clear text field messageEnterTextArea.setText(""); - contentPane.revalidate(); + + revalidate(); + repaint(); } catch (Exception e) { JOptionPane.showMessageDialog(this, "An exception occured while sending a message. See the log for more details.", diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index c3bebac..51cbbd5 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -1,9 +1,10 @@ package envoy.client.ui; -import java.awt.Component; import java.text.SimpleDateFormat; +import javax.swing.JComponent; import javax.swing.JLabel; +import javax.swing.border.EmptyBorder; import envoy.client.Settings; import envoy.client.ui.list.ComponentList; @@ -21,23 +22,22 @@ import envoy.data.Message; * @author Maximilian Käfer * @since Envoy v0.1-alpha */ -public class MessageListRenderer extends JLabel implements ComponentListCellRenderer { - - private static final long serialVersionUID = 5164417379767181198L; +public class MessageListRenderer implements ComponentListCellRenderer { @Override - public Component getListCellComponent(ComponentList list, Message value, boolean isSelected) { + public JComponent getListCellComponent(ComponentList list, Message value, boolean isSelected) { + final JLabel label = new JLabel(); if (isSelected) { - setBackground(Color.DARK_GRAY); - setForeground(Color.RED); -// setBackground(list.getSelectionBackground()); -// setForeground(list.getSelectionForeground()); + label.setBackground(Color.DARK_GRAY); + label.setForeground(Color.RED); + // setBackground(list.getSelectionBackground()); + // setForeground(list.getSelectionForeground()); } else { - setBackground(list.getBackground()); - setForeground(list.getForeground()); + label.setBackground(list.getBackground()); + label.setForeground(list.getForeground()); } - setOpaque(true); + label.setOpaque(true); // TODO: Handle message attachments @@ -51,12 +51,16 @@ public class MessageListRenderer extends JLabel implements ComponentListCellRend // Getting the DateColor in the Chat of the current theme String dateColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat().toHex(); - setText(String.format("

%s

%s :%s", + label.setText(String.format("

%s

%s :%s", dateColor, date, textColor, text, state)); - return this; + + // Define some space to the components above and below + label.setBorder(new EmptyBorder(0, 0, 15, 0)); + + return label; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 313838d..7cca24a 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -7,28 +7,34 @@ import javax.swing.JPanel; * Project: envoy-client
* File: ComponentList.java
* Created: 25.01.2020
- * + * * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ public class ComponentList extends JPanel { private ComponentListModel model; - private ComponentListCellRenderer renderer; + private ComponentListCellRenderer renderer; private static final long serialVersionUID = 1759644503942876737L; - public ComponentList(ComponentListModel model, ComponentListCellRenderer renderer) { + public ComponentList(ComponentListCellRenderer renderer) { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - this.model = model; - this.renderer = renderer; + this.renderer = renderer; + } + + public ComponentList(ComponentListModel model, ComponentListCellRenderer renderer) { + this(renderer); + this.model = model; setModel(model); } public void setModel(ComponentListModel model) { // Remove old model - this.model.clear(); - this.model.setComponentList(null); + if (this.model != null) { + this.model.clear(); + this.model.setComponentList(null); + } // Synchronize with new model this.model = model; @@ -40,9 +46,10 @@ public class ComponentList extends JPanel { add(renderer.getListCellComponent(this, elem, false)); } - private void synchronizeModel() { + void synchronizeModel() { removeAll(); - for (E elem : model) - add(renderer.getListCellComponent(this, elem, false)); + if (model != null) + for (E elem : model) + add(renderer.getListCellComponent(this, elem, false)); } } diff --git a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java b/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java index 95d196d..7fdab1b 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java +++ b/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java @@ -1,16 +1,16 @@ package envoy.client.ui.list; -import java.awt.Component; +import javax.swing.JComponent; /** * Project: envoy-client
* File: ComponentListCellRenderer.java
* Created: 25.01.2020
- * + * * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ public interface ComponentListCellRenderer { - Component getListCellComponent(ComponentList list, E value, boolean isSelected); + JComponent getListCellComponent(ComponentList list, E value, boolean isSelected); } diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java index 27db590..e4b0594 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -1,5 +1,6 @@ package envoy.client.ui.list; +import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -8,19 +9,21 @@ import java.util.List; * Project: envoy-client
* File: ComponentListModel.java
* Created: 25.01.2020
- * + * * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ -public final class ComponentListModel implements Iterable { +public final class ComponentListModel implements Iterable, Serializable { - private List elements = new ArrayList<>(); - private ComponentList componentList; + private List elements = new ArrayList<>(); + transient private ComponentList componentList; + + private static final long serialVersionUID = 4815005915255497331L; /** * Adds an element to this model and notifies the associated * {@link ComponentList} to add the corresponding component. - * + * * @param e the element to add * @return {@code true} * @see java.util.List#add(java.lang.Object) @@ -33,7 +36,7 @@ public final class ComponentListModel implements Iterable { /** * Removes all elements from this model and clears the associated * {@link ComponentList}. - * + * * @see java.util.List#clear() * @since Envoy v0.3-alpha */ @@ -52,7 +55,7 @@ public final class ComponentListModel implements Iterable { /** * Removes the element at a specific index from this model and the corresponding * component from the {@link ComponentList}. - * + * * @param index * @return the removed element * @see java.util.List#remove(int) @@ -66,6 +69,7 @@ public final class ComponentListModel implements Iterable { * @return * @see java.util.List#iterator() */ + @Override public Iterator iterator() { return new Iterator() { @@ -81,6 +85,6 @@ public final class ComponentListModel implements Iterable { void setComponentList(ComponentList componentList) { this.componentList = componentList; - if (componentList != null) elements.forEach(componentList::add); + if (componentList != null) componentList.synchronizeModel(); } } From df8eb4bac97e9ca5a89deb66c9c68eb5d7a14f8f Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 27 Jan 2020 20:23:30 +0100 Subject: [PATCH 197/474] Changed message list components to JPanels --- .../envoy/client/ui/MessageListRenderer.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 51cbbd5..11312d1 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -4,6 +4,7 @@ import java.text.SimpleDateFormat; import javax.swing.JComponent; import javax.swing.JLabel; +import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import envoy.client.Settings; @@ -26,19 +27,17 @@ public class MessageListRenderer implements ComponentListCellRenderer { @Override public JComponent getListCellComponent(ComponentList list, Message value, boolean isSelected) { - final JLabel label = new JLabel(); + final JPanel panel = new JPanel(); if (isSelected) { - label.setBackground(Color.DARK_GRAY); - label.setForeground(Color.RED); + panel.setBackground(Color.DARK_GRAY); + panel.setForeground(Color.RED); // setBackground(list.getSelectionBackground()); // setForeground(list.getSelectionForeground()); } else { - label.setBackground(list.getBackground()); - label.setForeground(list.getForeground()); + panel.setBackground(list.getBackground()); + panel.setForeground(list.getForeground()); } - label.setOpaque(true); - // TODO: Handle message attachments final String text = value.getText(); @@ -51,16 +50,18 @@ public class MessageListRenderer implements ComponentListCellRenderer { // Getting the DateColor in the Chat of the current theme String dateColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat().toHex(); - label.setText(String.format("

%s

%s :%s", + //JLabel textLabel = new JLabel(text + ": " + state); + + panel.add(new JLabel(String.format("

%s

%s :%s", dateColor, date, textColor, text, - state)); + state))); // Define some space to the components above and below - label.setBorder(new EmptyBorder(0, 0, 15, 0)); + panel.setBorder(new EmptyBorder(0, 0, 15, 0)); - return label; + return panel; } } \ No newline at end of file From 82b3a095511b42b512353dc4566ea1776d486bcb Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 27 Jan 2020 21:01:38 +0100 Subject: [PATCH 198/474] Added Javadoc for the ui.list package --- .../envoy/client/ui/list/ComponentList.java | 48 ++++++++++++++++--- .../ui/list/ComponentListCellRenderer.java | 14 ++++++ .../client/ui/list/ComponentListModel.java | 22 +++++++-- 3 files changed, 74 insertions(+), 10 deletions(-) diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 7cca24a..47f8c31 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -4,10 +4,15 @@ import javax.swing.BoxLayout; import javax.swing.JPanel; /** + * Provides a vertical list layout of components provided in a + * {@link ComponentListModel}. Similar to {@link javax.swing.JList} but capable + * of rendering {@link JPanel}s.
+ *
* Project: envoy-client
* File: ComponentList.java
* Created: 25.01.2020
* + * @param the type of object displayed in this list * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ @@ -18,17 +23,38 @@ public class ComponentList extends JPanel { private static final long serialVersionUID = 1759644503942876737L; + /** + * Creates an instance of {@link ComponentList}. + * + * @param renderer the list cell renderer used to display elements provided by + * the {@link ComponentListModel} + * @since Envoy v0.3-alpha + */ public ComponentList(ComponentListCellRenderer renderer) { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.renderer = renderer; } + /** + * Creates an instance of {@link ComponentList}. + * + * @param model the list model providing the list elements to render + * @param renderer the list cell renderer used to display elements provided by + * the {@link ComponentListModel} + * @since Envoy v0.3-alpha + */ public ComponentList(ComponentListModel model, ComponentListCellRenderer renderer) { this(renderer); this.model = model; setModel(model); } + /** + * Sets the list model providing the list elements to render + * + * @param model the list model to set + * @since Envoy v0.3-alpha + */ public void setModel(ComponentListModel model) { // Remove old model if (this.model != null) { @@ -42,14 +68,24 @@ public class ComponentList extends JPanel { synchronizeModel(); } - void add(E elem) { - add(renderer.getListCellComponent(this, elem, false)); - } + /** + * Adds an object to the list by rendering it with the current + * {@link ComponentListCellRenderer}. + * + * @param elem the element to add + * @since Envoy v0.3-alpha + */ + void add(E elem) { add(renderer.getListCellComponent(this, elem, false)); } + /** + * Removes all child components and then adds all components representing the + * elements of the {@link ComponentListModel}. + * + * @since Envoy v0.3-alpha + */ void synchronizeModel() { removeAll(); - if (model != null) - for (E elem : model) - add(renderer.getListCellComponent(this, elem, false)); + if (model != null) for (E elem : model) + add(renderer.getListCellComponent(this, elem, false)); } } diff --git a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java b/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java index 7fdab1b..a8bdda6 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java +++ b/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java @@ -3,14 +3,28 @@ package envoy.client.ui.list; import javax.swing.JComponent; /** + * Allows a {@link ComponentList} convert its elements into Swing components + * that can be rendered.
+ *
* Project: envoy-client
* File: ComponentListCellRenderer.java
* Created: 25.01.2020
* + * @param the type of object displayed in this list * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ public interface ComponentListCellRenderer { + /** + * Provides a Swing component representing a list element. + * + * @param list the list in which the component will be displayed + * @param value the list element that will be converted + * @param isSelected {@code true} if the user has selected the list cell in + * which the list element is rendered + * @return the component representing the list element + * @since Envoy v0.3-alpha + */ JComponent getListCellComponent(ComponentList list, E value, boolean isSelected); } diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java index e4b0594..1845651 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -6,10 +6,13 @@ import java.util.Iterator; import java.util.List; /** + * Stores objects that will be displayed in a {@link ComponentList}.
+ *
* Project: envoy-client
* File: ComponentListModel.java
* Created: 25.01.2020
* + * @param the type of object displayed in this list * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ @@ -27,6 +30,7 @@ public final class ComponentListModel implements Iterable, Serializable { * @param e the element to add * @return {@code true} * @see java.util.List#add(java.lang.Object) + * @since Envoy v0.3-alpha */ public boolean add(E e) { if (componentList != null) componentList.add(e); @@ -46,9 +50,10 @@ public final class ComponentListModel implements Iterable, Serializable { } /** - * @param index - * @return + * @param index the index to retrieve the element from + * @return the element located at the index * @see java.util.List#get(int) + * @since Envoy v0.3-alpha */ public E get(int index) { return elements.get(index); } @@ -56,9 +61,10 @@ public final class ComponentListModel implements Iterable, Serializable { * Removes the element at a specific index from this model and the corresponding * component from the {@link ComponentList}. * - * @param index + * @param index the index of the element to remove * @return the removed element * @see java.util.List#remove(int) + * @since Envoy v0.3-alpha */ public E remove(int index) { if (componentList != null) componentList.remove(index); @@ -66,8 +72,9 @@ public final class ComponentListModel implements Iterable, Serializable { } /** - * @return + * @return an iterator over the elements of this list model * @see java.util.List#iterator() + * @since Envoy v0.3-alpha */ @Override public Iterator iterator() { @@ -83,6 +90,13 @@ public final class ComponentListModel implements Iterable, Serializable { }; } + /** + * Sets the component list displaying the elements of this model and triggers a + * synchronization. + * + * @param componentList the component list to set + * @since Envoy v0.3-alpha + */ void setComponentList(ComponentList componentList) { this.componentList = componentList; if (componentList != null) componentList.synchronizeModel(); From 425f52f6fddcfc290edef9189b343d12e06ede98 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 29 Jan 2020 07:44:25 +0100 Subject: [PATCH 199/474] Implemented message ID generation and generator requests * Persisting IdGenerator in LocalDB * Added Client#requestIdGenerator() * Listening to MessageCreationEvents in ChatWindow --- pom.xml | 2 +- src/main/java/envoy/client/Client.java | 33 ++++++++++-- src/main/java/envoy/client/LocalDB.java | 53 ++++++++++++++++--- src/main/java/envoy/client/ui/ChatWindow.java | 25 +++++++-- src/main/java/envoy/client/ui/Startup.java | 5 +- 5 files changed, 100 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index bf35cbb..0b5487d 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - e5c67b8 + develop-SNAPSHOT diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 4885a92..935669f 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -11,6 +11,7 @@ import javax.naming.TimeLimitExceededException; import envoy.client.util.EnvoyLog; import envoy.data.*; +import envoy.event.IdGeneratorRequest; import envoy.util.SerializationUtils; /** @@ -45,11 +46,13 @@ public class Client implements Closeable { * an exception is thrown. * * @param credentials the login credentials of the user + * @param localDB the local database used to persist the current + * {@link IdGenerator} * @throws Exception if the online mode could not be entered or the request * failed for some other reason * @since Envoy v0.2-alpha */ - public void onlineInit(LoginCredentials credentials) throws Exception { + public void onlineInit(LoginCredentials credentials, LocalDB localDB) throws Exception { // Establish TCP connection logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); socket = new Socket(config.getServer(), config.getPort()); @@ -84,21 +87,38 @@ public class Client implements Closeable { // Register processors for message and status handling receiver.registerProcessor(Message.class, new ReceivedMessageProcessor()); + // TODO: Status handling + + // Process message ID generation + receiver.registerProcessor(IdGenerator.class, localDB::setIdGenerator); + + // Request a generator if none is present + if (!localDB.hasIdGenerator() || !localDB.getIdGenerator().hasNext()) requestIdGenerator(); } /** * Sends a message to the server. - * + * * @param message the message to send * @throws IOException if the message does not reach the server * @since Envoy v0.3-alpha */ public void sendMessage(Message message) throws IOException { - checkOnline(); - SerializationUtils.writeBytesWithLength(message, socket.getOutputStream()); + writeObject(message); message.nextStatus(); } + /** + * Requests a new {@link IdGenerator} from the server. + * + * @throws IOException if the request does not reach the server + * @since Envoy v0.3-alpha + */ + public void requestIdGenerator() throws IOException { + logger.info("Requesting new id generator..."); + writeObject(new IdGeneratorRequest()); + } + /** * @return a {@code Map} of all users on the server with their * user names as keys @@ -114,6 +134,11 @@ public class Client implements Closeable { @Override public void close() throws IOException { if (online) socket.close(); } + private void writeObject(Object obj) throws IOException { + checkOnline(); + SerializationUtils.writeBytesWithLength(obj, socket.getOutputStream()); + } + private void checkOnline() { if (!online) throw new IllegalStateException("Client is not online"); } /** diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 2c40e65..7511d41 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -4,10 +4,15 @@ import java.io.File; import java.io.IOException; import java.util.*; +import envoy.data.IdGenerator; import envoy.data.User; import envoy.util.SerializationUtils; /** + * Stored information about the current {@link User} and their {@link Chat}s. + * For message ID generation a {@link IdGenerator} is stored as well. + * These object are persisted inside a folder of the local file system.
+ *
* Project: envoy-client
* File: LocalDB.java
* Created: 27.10.2019
@@ -18,10 +23,11 @@ import envoy.util.SerializationUtils; */ public class LocalDB { - private File localDBDir, localDBFile, usersFile; + private File localDBDir, localDBFile, usersFile, idGeneratorFile; private User user; private Map users = new HashMap<>(); private List chats = new ArrayList<>(); + private IdGenerator idGenerator; /** * Constructs an empty local database. To serialize any chats to the file @@ -37,7 +43,8 @@ public class LocalDB { // Initialize local database directory if (localDBDir.exists() && !localDBDir.isDirectory()) throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - usersFile = new File(localDBDir, "users.db"); + usersFile = new File(localDBDir, "users.db"); + idGeneratorFile = new File(localDBDir, "id_generator.db"); } /** @@ -53,7 +60,8 @@ public class LocalDB { /** * Stores all users to the local database. If the client user is specified, the - * chats related to this user are stored as well. + * chats related to this user are stored as well. The message id generator will + * also be saved if present. * * @throws IOException if something went wrong during saving * @since Envoy v0.1-alpha @@ -63,12 +71,15 @@ public class LocalDB { SerializationUtils.write(usersFile, users); // Save chats - SerializationUtils.write(localDBFile, chats); + if (user != null) SerializationUtils.write(localDBFile, chats); + + // Save id generator + if (hasIdGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator); } /** * Loads all users that are stored in the local database. - * + * * @throws IOException if the loading process failed * @throws ClassNotFoundException if the loading process failed * @since Envoy v0.2-alpha @@ -77,13 +88,25 @@ public class LocalDB { /** * Loads all chats saved by Envoy for the client user. - * + * * @throws IOException if the loading process failed * @throws ClassNotFoundException if the loading process failed * @since Envoy v0.1-alpha */ public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } + /** + * Loads the message ID generator that is stored in the local database. If the + * file is not found, the exception is ignored. + * + * @since Envoy v0.3-alpha + */ + public void loadIdGenerator() { + try { + idGenerator = SerializationUtils.read(idGeneratorFile, IdGenerator.class); + } catch (ClassNotFoundException | IOException e) {} + } + /** * @return a {@code Map} of all users stored locally with their * user names as keys @@ -119,4 +142,22 @@ public class LocalDB { * @since Envoy v0.2-alpha */ public void setUser(User user) { this.user = user; } + + /** + * @return the message ID generator + * @since Envoy v0.3-alpha + */ + public IdGenerator getIdGenerator() { return idGenerator; } + + /** + * @param idGenerator the message ID generator to set + * @since Envoy v0.3-alpha + */ + public void setIdGenerator(IdGenerator idGenerator) { this.idGenerator = idGenerator; } + + /** + * @return {@code true} if an {@link IdGenerator} is present + * @since Envoy v0.3-alpha + */ + public boolean hasIdGenerator() { return idGenerator != null; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 3c4cdee..51c7d7f 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -10,6 +10,7 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; import envoy.client.*; +import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.list.ComponentList; import envoy.client.ui.settings.SettingsScreen; @@ -175,7 +176,9 @@ public class ChatWindow extends JFrame { messageList.setModel(currentChat.getModel()); scrollPane.setChatOpened(true); - contentPane.revalidate(); + + revalidate(); + repaint(); } }); @@ -194,13 +197,20 @@ public class ChatWindow extends JFrame { contentPane.add(userList, gbc_userList); contentPane.revalidate(); + // Listen to theme changes EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get())); + // Listen to received messages + EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { + Message message = ((MessageCreationEvent) evt).get(); + localDB.getChats().stream().filter(c -> c.getRecipient().getId() == message.getRecipientId()).findFirst().get().appendMessage(message); + }); + contentPane.revalidate(); } /** - * Used to immediately reload the ChatWindow when settings were changed. + * Used to immediately reload the {@link ChatWindow} when settings were changed. * * @param theme the theme to change colors into * @since Envoy v0.2-alpha @@ -247,7 +257,7 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { // Create message - final Message message = new MessageBuilder(localDB.getUser().getId(), currentChat.getRecipient().getId()) + final Message message = new MessageBuilder(localDB.getUser().getId(), currentChat.getRecipient().getId(), localDB.getIdGenerator()) .setText(messageEnterTextArea.getText()) .build(); @@ -262,12 +272,17 @@ public class ChatWindow extends JFrame { // Clear text field messageEnterTextArea.setText(""); + // Update UI revalidate(); repaint(); + + // Request a new id generator if all ids were used + if (!localDB.getIdGenerator().hasNext()) client.requestIdGenerator(); + } catch (Exception e) { JOptionPane.showMessageDialog(this, - "An exception occured while sending a message. See the log for more details.", - "Exception occured", + "Error sending message:\n" + e.toString(), + "Message sending error", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 3e4692d..2fb9a3a 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -62,7 +62,7 @@ public class Startup { if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined"); } catch (Exception e) { JOptionPane - .showMessageDialog(null, "Error loading configuration values: \n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE); + .showMessageDialog(null, "Error loading configuration values:\n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE); System.exit(1); e.printStackTrace(); } @@ -97,7 +97,8 @@ public class Startup { Client client = new Client(); try { // Try entering online mode first - client.onlineInit(credentials); + localDB.loadIdGenerator(); + client.onlineInit(credentials, localDB); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); e1.printStackTrace(); From ab6d27651ed3d273f45e8dc172bf133027fd2f47 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 1 Feb 2020 10:20:06 +0100 Subject: [PATCH 200/474] Removed old sync thread, implemented chat reading --- src/main/java/envoy/client/Chat.java | 29 ++++++--- src/main/java/envoy/client/Config.java | 9 +-- src/main/java/envoy/client/Settings.java | 4 +- src/main/java/envoy/client/ui/ChatWindow.java | 60 ++----------------- src/main/java/envoy/client/ui/Startup.java | 2 +- .../client/ui/list/ComponentListModel.java | 7 +++ 6 files changed, 37 insertions(+), 74 deletions(-) diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index 20513e4..a00e46d 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -4,6 +4,7 @@ import java.io.Serializable; import envoy.client.ui.list.ComponentListModel; import envoy.data.Message; +import envoy.data.Message.MessageStatus; import envoy.data.User; /** @@ -36,22 +37,34 @@ public class Chat implements Serializable { public Chat(User recipient) { this.recipient = recipient; } /** - * @return the recipient of a message - * @since Envoy v0.1-alpha - */ - public User getRecipient() { return recipient; } - - /** - * Adds the received message at the current Point in the current chat + * Appends a message to the bottom of this chat * - * @param message the message to add in said chat + * @param message the message to append * @since Envoy v0.1-alpha */ public void appendMessage(Message message) { model.add(message); } + /** + * Sets the status of all chat messages to {@code READ} starting from the bottom + * and stopping once a read message is found. + * + * @since Envoy v0.3-alpha + */ + public void read() { + for (int i = model.size() - 1; i >= 0; --i) + if (model.get(i).getStatus() == MessageStatus.READ) break; + else model.get(i).setStatus(MessageStatus.READ); + } + /** * @return all messages in the current chat * @since Envoy v0.1-alpha */ public ComponentListModel getModel() { return model; } + + /** + * @return the recipient of a message + * @since Envoy v0.1-alpha + */ + public User getRecipient() { return recipient; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index 9a2c08b..fc93a08 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -31,7 +31,6 @@ public class Config { items.put("server", new ConfigItem<>("server", "s", (input) -> input, null)); items.put("port", new ConfigItem<>("port", "p", (input) -> Integer.parseInt(input), null)); items.put("localDB", new ConfigItem<>("localDB", "db", (input) -> new File(input), new File("localDB"))); - items.put("syncTimeout", new ConfigItem<>("syncTimeout", "st", (input) -> Integer.parseInt(input), 1000)); items.put("homeDirectory", new ConfigItem<>("homeDirectory", "h", (input) -> new File(input), new File(System.getProperty("user.home"), ".envoy"))); items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", (input) -> Level.parse(input), Level.CONFIG)); @@ -112,7 +111,7 @@ public class Config { * @return the port at which the Envoy server is located on the host * @since Envoy v0.1-alpha */ - public int getPort() { return (int) items.get("port").get(); } + public Integer getPort() { return (Integer) items.get("port").get(); } /** * @return the local database specific to the client user @@ -120,12 +119,6 @@ public class Config { */ public File getLocalDB() { return (File) items.get("localDB").get(); } - /** - * @return the current time (milliseconds) that is waited between Syncs - * @since Envoy v0.1-alpha - */ - public int getSyncTimeout() { return (int) items.get("syncTimeout").get(); } - /** * @return the directory in which all local files are saves * @since Envoy v0.2-alpha diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index ef451d0..02b6c88 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -135,7 +135,7 @@ public class Settings { * {@code Control} key. * @since Envoy v0.2-alpha */ - public boolean isEnterToSend() { return (boolean) items.get("enterToSend").get(); } + public Boolean isEnterToSend() { return (Boolean) items.get("enterToSend").get(); } /** * Changes the keystrokes performed by the user to send a message. @@ -152,7 +152,7 @@ public class Settings { * @return the current on close mode. * @since Envoy v0.3-alpha */ - public boolean getCurrentOnCloseMode() { return (boolean) items.get("onCloseMode").get(); } + public Boolean getCurrentOnCloseMode() { return (Boolean) items.get("onCloseMode").get(); } /** * Sets the current on close mode. diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 51c7d7f..30ea1ea 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -169,7 +169,7 @@ public class ChatWindow extends JFrame { currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); // Set all unread messages in the chat to read - readCurrentChat(); + currentChat.read(); client.setRecipient(user); textPane.setText(currentChat.getRecipient().getName()); @@ -204,9 +204,11 @@ public class ChatWindow extends JFrame { EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { Message message = ((MessageCreationEvent) evt).get(); localDB.getChats().stream().filter(c -> c.getRecipient().getId() == message.getRecipientId()).findFirst().get().appendMessage(message); + revalidate(); + repaint(); }); - contentPane.revalidate(); + revalidate(); } /** @@ -309,64 +311,13 @@ public class ChatWindow extends JFrame { } /** - * Updates the data model and the UI repeatedly after a certain amount of - * time. - * - * @param timeout the amount of time that passes between two requests sent to - * the server - * @since Envoy v0.1-alpha - */ - private void startSyncThread(int timeout) { - new Timer(timeout, (evt) -> { - new Thread(() -> { - - // Synchronize - try { - // localDB.applySync(client.sendSync(client.getSender().getId(), - // localDB.fillSync(client.getSender().getId()))); - } catch (Exception e) { - logger.log(Level.SEVERE, "Could not perform sync", e); - } - - // TODO: Process unread messages - // localDB.addUnreadMessagesToLocalDB(); - // localDB.clearUnreadMessagesSync(); - - // Mark unread messages as read when they are in the current chat - readCurrentChat(); - - // Update UI - SwingUtilities.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); - }).start(); - }).start(); - } - - private void updateUserStates() { - for (int i = 0; i < userList.getModel().getSize(); i++) - for (int j = 0; j < localDB.getChats().size(); j++) - if (userList.getModel().getElementAt(i).getId() == localDB.getChats().get(j).getRecipient().getId()) - userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); - } - - /** - * Marks messages in the current chat as {@code READ}. - */ - private void readCurrentChat() { - if (currentChat != null) { - // TODO: localDB.setMessagesToRead(currentChat); - } - } - - /** - * Sets the {@link Client} used by this {@link ChatWindow}. If the client is - * online, the sync thread is started. + * Sets the {@link Client} used by this {@link ChatWindow}. * * @param client the {@link Client} used to send and receive messages * @since Envoy v0.2-alpha */ public void setClient(Client client) { this.client = client; - if (client.isOnline() && localDB != null) startSyncThread(Config.getInstance().getSyncTimeout()); } /** @@ -379,6 +330,5 @@ public class ChatWindow extends JFrame { public void setLocalDB(LocalDB localDB) { this.localDB = localDB; loadUsersAndChats(); - if (client != null && client.isOnline()) startSyncThread(Config.getInstance().getSyncTimeout()); } } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 2fb9a3a..949b464 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -153,7 +153,7 @@ public class Startup { .getItems() .get("onCloseMode") .setChangeHandler((onCloseMode) -> chatWindow - .setDefaultCloseOperation((boolean) onCloseMode ? JFrame.HIDE_ON_CLOSE : JFrame.EXIT_ON_CLOSE)); + .setDefaultCloseOperation((Boolean) onCloseMode ? JFrame.HIDE_ON_CLOSE : JFrame.EXIT_ON_CLOSE)); } catch (EnvoyException e) { logger.warning("The StatusTrayIcon is not supported on this platform!"); } diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java index 1845651..8fb1d68 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -71,6 +71,13 @@ public final class ComponentListModel implements Iterable, Serializable { return elements.remove(index); } + /** + * @return the amount of elements in this list model + * @see java.util.List#size() + * @since Envoy v0.3-alpha + */ + public int size() { return elements.size(); } + /** * @return an iterator over the elements of this list model * @see java.util.List#iterator() From 2436afc8e93883b9ce1bf07eaefc98d8ead52b2a Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 1 Feb 2020 10:41:59 +0100 Subject: [PATCH 201/474] Fixed receiving messages --- src/main/java/envoy/client/ui/ChatWindow.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 30ea1ea..da64632 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -203,7 +203,7 @@ public class ChatWindow extends JFrame { // Listen to received messages EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { Message message = ((MessageCreationEvent) evt).get(); - localDB.getChats().stream().filter(c -> c.getRecipient().getId() == message.getRecipientId()).findFirst().get().appendMessage(message); + localDB.getChats().stream().filter(c -> c.getRecipient().getId() == message.getSenderId()).findFirst().get().appendMessage(message); revalidate(); repaint(); }); From 689b8bdf8d0f887c78dfe3bce28398f48114321d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 1 Feb 2020 11:34:57 +0100 Subject: [PATCH 202/474] Fixed spacing in ComponentList --- src/main/java/envoy/client/ui/ChatWindow.java | 5 ++++- .../envoy/client/ui/list/ComponentList.java | 18 +++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index da64632..ab9e968 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -166,14 +166,17 @@ public class ChatWindow extends JFrame { final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); + // Select current chat currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); - // Set all unread messages in the chat to read + // Read current Chat currentChat.read(); + // Set recipient in client and chat title client.setRecipient(user); textPane.setText(currentChat.getRecipient().getName()); + // Update model and scroll down messageList.setModel(currentChat.getModel()); scrollPane.setChatOpened(true); diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 47f8c31..5b2ea45 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -1,6 +1,9 @@ package envoy.client.ui.list; +import java.awt.Dimension; + import javax.swing.BoxLayout; +import javax.swing.JComponent; import javax.swing.JPanel; /** @@ -57,10 +60,8 @@ public class ComponentList extends JPanel { */ public void setModel(ComponentListModel model) { // Remove old model - if (this.model != null) { - this.model.clear(); + if (this.model != null) this.model.setComponentList(null); - } // Synchronize with new model this.model = model; @@ -75,7 +76,14 @@ public class ComponentList extends JPanel { * @param elem the element to add * @since Envoy v0.3-alpha */ - void add(E elem) { add(renderer.getListCellComponent(this, elem, false)); } + void add(E elem) { + JComponent c = renderer.getListCellComponent(this, elem, false); + Dimension size = new Dimension(getWidth(), 50); + c.setMaximumSize(size); + c.setMinimumSize(size); + c.setPreferredSize(size); + add(c); + } /** * Removes all child components and then adds all components representing the @@ -86,6 +94,6 @@ public class ComponentList extends JPanel { void synchronizeModel() { removeAll(); if (model != null) for (E elem : model) - add(renderer.getListCellComponent(this, elem, false)); + add(elem); } } From a39ea7adb1229e20ecfe0fd6967da6ba154a4a78 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 2 Feb 2020 11:37:46 +0100 Subject: [PATCH 203/474] Moved dimension and spacing calculation to MessageListRenderer --- .../envoy/client/ui/MessageListRenderer.java | 19 +++++++++++-------- .../envoy/client/ui/list/ComponentList.java | 10 +--------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 11312d1..c038e39 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -1,11 +1,9 @@ package envoy.client.ui; +import java.awt.Dimension; import java.text.SimpleDateFormat; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.border.EmptyBorder; +import javax.swing.*; import envoy.client.Settings; import envoy.client.ui.list.ComponentList; @@ -31,6 +29,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { if (isSelected) { panel.setBackground(Color.DARK_GRAY); panel.setForeground(Color.RED); + // TODO: Selection // setBackground(list.getSelectionBackground()); // setForeground(list.getSelectionForeground()); } else { @@ -50,8 +49,6 @@ public class MessageListRenderer implements ComponentListCellRenderer { // Getting the DateColor in the Chat of the current theme String dateColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat().toHex(); - //JLabel textLabel = new JLabel(text + ": " + state); - panel.add(new JLabel(String.format("

%s

%s :%s", dateColor, date, @@ -59,8 +56,14 @@ public class MessageListRenderer implements ComponentListCellRenderer { text, state))); - // Define some space to the components above and below - panel.setBorder(new EmptyBorder(0, 0, 15, 0)); + // Define some space to the messages below + panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0), BorderFactory.createEtchedBorder())); + + // Define a maximum height of 50px + Dimension size = new Dimension(list.getWidth() - 25, 50); + panel.setMaximumSize(size); + panel.setMinimumSize(size); + panel.setPreferredSize(size); return panel; } diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 5b2ea45..8cbf2db 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -1,9 +1,6 @@ package envoy.client.ui.list; -import java.awt.Dimension; - import javax.swing.BoxLayout; -import javax.swing.JComponent; import javax.swing.JPanel; /** @@ -77,12 +74,7 @@ public class ComponentList extends JPanel { * @since Envoy v0.3-alpha */ void add(E elem) { - JComponent c = renderer.getListCellComponent(this, elem, false); - Dimension size = new Dimension(getWidth(), 50); - c.setMaximumSize(size); - c.setMinimumSize(size); - c.setPreferredSize(size); - add(c); + add(renderer.getListCellComponent(this, elem, false)); } /** From 123e51c8d58300dfd36a6b7968c5087174e59066 Mon Sep 17 00:00:00 2001 From: delvh Date: Sun, 2 Feb 2020 13:44:10 +0100 Subject: [PATCH 204/474] Moved Receiver + ReceivedMessageProcessor in the net package additionally added serialVersionUIDs for the Event classes --- src/main/java/envoy/client/Client.java | 2 ++ src/main/java/envoy/client/event/MessageCreationEvent.java | 2 ++ src/main/java/envoy/client/event/MessageEvent.java | 2 ++ src/main/java/envoy/client/event/MessageModificationEvent.java | 2 ++ src/main/java/envoy/client/event/ThemeChangeEvent.java | 3 ++- .../java/envoy/client/{ => net}/ReceivedMessageProcessor.java | 2 +- src/main/java/envoy/client/{ => net}/Receiver.java | 2 +- 7 files changed, 12 insertions(+), 3 deletions(-) rename src/main/java/envoy/client/{ => net}/ReceivedMessageProcessor.java (97%) rename src/main/java/envoy/client/{ => net}/Receiver.java (99%) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 935669f..8ed3bb4 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -9,6 +9,8 @@ import java.util.logging.Logger; import javax.naming.TimeLimitExceededException; +import envoy.client.net.ReceivedMessageProcessor; +import envoy.client.net.Receiver; import envoy.client.util.EnvoyLog; import envoy.data.*; import envoy.event.IdGeneratorRequest; diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java index 36397d9..301603e 100644 --- a/src/main/java/envoy/client/event/MessageCreationEvent.java +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -11,6 +11,8 @@ import envoy.data.Message; */ public class MessageCreationEvent extends MessageEvent { + private static final long serialVersionUID = -6451021678064566774L; + /** * @param message the {@link Message} that has been created */ diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java index a1b5c68..8bd05d1 100644 --- a/src/main/java/envoy/client/event/MessageEvent.java +++ b/src/main/java/envoy/client/event/MessageEvent.java @@ -12,6 +12,8 @@ import envoy.event.Event; */ public class MessageEvent implements Event { + private static final long serialVersionUID = 7658989461923112804L; + /** * the {@link Message} attached to this {@link MessageEvent}. */ diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java index 248c6f1..3a5549a 100644 --- a/src/main/java/envoy/client/event/MessageModificationEvent.java +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -11,6 +11,8 @@ import envoy.data.Message; */ public class MessageModificationEvent extends MessageEvent { + private static final long serialVersionUID = 4650039506439563116L; + /** * @param message the {@link Message} that has been modified */ diff --git a/src/main/java/envoy/client/event/ThemeChangeEvent.java b/src/main/java/envoy/client/event/ThemeChangeEvent.java index adb9707..02a15df 100644 --- a/src/main/java/envoy/client/event/ThemeChangeEvent.java +++ b/src/main/java/envoy/client/event/ThemeChangeEvent.java @@ -13,7 +13,8 @@ import envoy.event.Event; */ public class ThemeChangeEvent implements Event { - private final Theme theme; + private static final long serialVersionUID = 6756772448803774547L; + private final Theme theme; /** * Initializes a {@link ThemeChangeEvent} conveying information about the change diff --git a/src/main/java/envoy/client/ReceivedMessageProcessor.java b/src/main/java/envoy/client/net/ReceivedMessageProcessor.java similarity index 97% rename from src/main/java/envoy/client/ReceivedMessageProcessor.java rename to src/main/java/envoy/client/net/ReceivedMessageProcessor.java index d408993..27b505e 100644 --- a/src/main/java/envoy/client/ReceivedMessageProcessor.java +++ b/src/main/java/envoy/client/net/ReceivedMessageProcessor.java @@ -1,4 +1,4 @@ -package envoy.client; +package envoy.client.net; import java.util.function.Consumer; import java.util.logging.Logger; diff --git a/src/main/java/envoy/client/Receiver.java b/src/main/java/envoy/client/net/Receiver.java similarity index 99% rename from src/main/java/envoy/client/Receiver.java rename to src/main/java/envoy/client/net/Receiver.java index e6cd3c5..5030241 100644 --- a/src/main/java/envoy/client/Receiver.java +++ b/src/main/java/envoy/client/net/Receiver.java @@ -1,4 +1,4 @@ -package envoy.client; +package envoy.client.net; import java.io.ByteArrayInputStream; import java.io.InputStream; From 664717140d32f0bf52ad838659d78fb7729508dc Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 3 Feb 2020 06:57:19 +0100 Subject: [PATCH 205/474] Fixed message reading --- src/main/java/envoy/client/Chat.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index a00e46d..b51f068 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -45,15 +45,18 @@ public class Chat implements Serializable { public void appendMessage(Message message) { model.add(message); } /** - * Sets the status of all chat messages to {@code READ} starting from the bottom - * and stopping once a read message is found. - * + * Sets the status of all chat messages received from the recipient to + * {@code READ} starting from the bottom and stopping once a read message is + * found. + * * @since Envoy v0.3-alpha */ public void read() { for (int i = model.size() - 1; i >= 0; --i) - if (model.get(i).getStatus() == MessageStatus.READ) break; - else model.get(i).setStatus(MessageStatus.READ); + if (model.get(i).getSenderId() == recipient.getId()) { + if (model.get(i).getStatus() == MessageStatus.READ) break; + else model.get(i).setStatus(MessageStatus.READ); + } } /** From 9d194967f5771db8a9e5c3aa31a5ed34b76b37e8 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 3 Feb 2020 21:52:48 +0100 Subject: [PATCH 206/474] Made local database persistence optional * Split LocalDB into abstract class LocalDb and PersistentLocalDb and TransientLocalDb * Moved LocalDb to database package * Added ignoreLocalDb option to Config --- src/main/java/envoy/client/Client.java | 13 +- src/main/java/envoy/client/Config.java | 13 +- src/main/java/envoy/client/LocalDB.java | 163 ------------------ .../java/envoy/client/database/LocalDb.java | 119 +++++++++++++ .../client/database/PersistentLocalDb.java | 93 ++++++++++ .../client/database/TransientLocalDb.java | 15 ++ src/main/java/envoy/client/ui/ChatWindow.java | 37 ++-- src/main/java/envoy/client/ui/Startup.java | 48 ++++-- 8 files changed, 294 insertions(+), 207 deletions(-) delete mode 100644 src/main/java/envoy/client/LocalDB.java create mode 100644 src/main/java/envoy/client/database/LocalDb.java create mode 100644 src/main/java/envoy/client/database/PersistentLocalDb.java create mode 100644 src/main/java/envoy/client/database/TransientLocalDb.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 8ed3bb4..a71f38e 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -9,6 +9,7 @@ import java.util.logging.Logger; import javax.naming.TimeLimitExceededException; +import envoy.client.database.LocalDb; import envoy.client.net.ReceivedMessageProcessor; import envoy.client.net.Receiver; import envoy.client.util.EnvoyLog; @@ -47,14 +48,14 @@ public class Client implements Closeable { * will block for up to 5 seconds. If the handshake does exceed this time limit, * an exception is thrown. * - * @param credentials the login credentials of the user - * @param localDB the local database used to persist the current - * {@link IdGenerator} + * @param credentials the login credentials of the user + * @param localDb the local database used to persist the current + * {@link IdGenerator} * @throws Exception if the online mode could not be entered or the request * failed for some other reason * @since Envoy v0.2-alpha */ - public void onlineInit(LoginCredentials credentials, LocalDB localDB) throws Exception { + public void onlineInit(LoginCredentials credentials, LocalDb localDb) throws Exception { // Establish TCP connection logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); socket = new Socket(config.getServer(), config.getPort()); @@ -92,10 +93,10 @@ public class Client implements Closeable { // TODO: Status handling // Process message ID generation - receiver.registerProcessor(IdGenerator.class, localDB::setIdGenerator); + receiver.registerProcessor(IdGenerator.class, localDb::setIdGenerator); // Request a generator if none is present - if (!localDB.hasIdGenerator() || !localDB.getIdGenerator().hasNext()) requestIdGenerator(); + if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator(); } /** diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index fc93a08..24e7780 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -1,9 +1,7 @@ package envoy.client; import java.io.File; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; +import java.util.*; import java.util.logging.Level; import envoy.exception.EnvoyException; @@ -31,6 +29,7 @@ public class Config { items.put("server", new ConfigItem<>("server", "s", (input) -> input, null)); items.put("port", new ConfigItem<>("port", "p", (input) -> Integer.parseInt(input), null)); items.put("localDB", new ConfigItem<>("localDB", "db", (input) -> new File(input), new File("localDB"))); + items.put("ignoreLocalDB", new ConfigItem<>("ignoreLocalDB", "nodb", (input) -> Boolean.parseBoolean(input), false)); items.put("homeDirectory", new ConfigItem<>("homeDirectory", "h", (input) -> new File(input), new File(System.getProperty("user.home"), ".envoy"))); items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", (input) -> Level.parse(input), Level.CONFIG)); @@ -99,7 +98,7 @@ public class Config { * @return {@code true} if server, port and localDB directory are known. * @since Envoy v0.1-alpha */ - public boolean isInitialized() { return items.values().stream().noneMatch(item -> item.get() == null); } + public boolean isInitialized() { return items.values().stream().map(ConfigItem::get).noneMatch(Objects::isNull); } /** * @return the host name of the Envoy server @@ -119,6 +118,12 @@ public class Config { */ public File getLocalDB() { return (File) items.get("localDB").get(); } + /** + * @return {@code true} if the local database is to be ignored + * @since Envoy v0.3-alpha + */ + public Boolean isIgnoreLocalDB() { return (Boolean) items.get("ignoreLocalDB").get(); } + /** * @return the directory in which all local files are saves * @since Envoy v0.2-alpha diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java deleted file mode 100644 index 7511d41..0000000 --- a/src/main/java/envoy/client/LocalDB.java +++ /dev/null @@ -1,163 +0,0 @@ -package envoy.client; - -import java.io.File; -import java.io.IOException; -import java.util.*; - -import envoy.data.IdGenerator; -import envoy.data.User; -import envoy.util.SerializationUtils; - -/** - * Stored information about the current {@link User} and their {@link Chat}s. - * For message ID generation a {@link IdGenerator} is stored as well. - * These object are persisted inside a folder of the local file system.
- *
- * Project: envoy-client
- * File: LocalDB.java
- * Created: 27.10.2019
- * - * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @since Envoy v0.1-alpha - */ -public class LocalDB { - - private File localDBDir, localDBFile, usersFile, idGeneratorFile; - private User user; - private Map users = new HashMap<>(); - private List chats = new ArrayList<>(); - private IdGenerator idGenerator; - - /** - * Constructs an empty local database. To serialize any chats to the file - * system, call {@link LocalDB#initializeDBFile()}. - * - * @param localDBDir the directory in which to store users and chats - * @throws IOException if the LocalDB could not be initialized - * @since Envoy v0.1-alpha - */ - public LocalDB(File localDBDir) throws IOException { - this.localDBDir = localDBDir; - - // Initialize local database directory - if (localDBDir.exists() && !localDBDir.isDirectory()) - throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - usersFile = new File(localDBDir, "users.db"); - idGeneratorFile = new File(localDBDir, "id_generator.db"); - } - - /** - * Creates a database file for a user-specific list of chats. - * - * @throws NullPointerException if the client user is not yet specified - * @since Envoy v0.1-alpha - */ - public void initializeDBFile() { - if (user == null) throw new NullPointerException("Client user is null"); - localDBFile = new File(localDBDir, user.getId() + ".db"); - } - - /** - * Stores all users to the local database. If the client user is specified, the - * chats related to this user are stored as well. The message id generator will - * also be saved if present. - * - * @throws IOException if something went wrong during saving - * @since Envoy v0.1-alpha - */ - public void save() throws IOException { - // Save users - SerializationUtils.write(usersFile, users); - - // Save chats - if (user != null) SerializationUtils.write(localDBFile, chats); - - // Save id generator - if (hasIdGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator); - } - - /** - * Loads all users that are stored in the local database. - * - * @throws IOException if the loading process failed - * @throws ClassNotFoundException if the loading process failed - * @since Envoy v0.2-alpha - */ - public void loadUsers() throws ClassNotFoundException, IOException { users = SerializationUtils.read(usersFile, HashMap.class); } - - /** - * Loads all chats saved by Envoy for the client user. - * - * @throws IOException if the loading process failed - * @throws ClassNotFoundException if the loading process failed - * @since Envoy v0.1-alpha - */ - public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } - - /** - * Loads the message ID generator that is stored in the local database. If the - * file is not found, the exception is ignored. - * - * @since Envoy v0.3-alpha - */ - public void loadIdGenerator() { - try { - idGenerator = SerializationUtils.read(idGeneratorFile, IdGenerator.class); - } catch (ClassNotFoundException | IOException e) {} - } - - /** - * @return a {@code Map} of all users stored locally with their - * user names as keys - * @since Envoy v0.2-alpha - */ - public Map getUsers() { return users; } - - /** - * @param users the users to set - */ - public void setUsers(Map users) { this.users = users; } - - /** - * @return all saved {@link Chat} objects that list the client user as the - * sender - * @since Envoy v0.1-alpha - **/ - public List getChats() { return chats; } - - /** - * @param chats the chats to set - */ - public void setChats(List chats) { this.chats = chats; } - - /** - * @return the {@link User} who initialized the local database - * @since Envoy v0.2-alpha - */ - public User getUser() { return user; } - - /** - * @param user the user to set - * @since Envoy v0.2-alpha - */ - public void setUser(User user) { this.user = user; } - - /** - * @return the message ID generator - * @since Envoy v0.3-alpha - */ - public IdGenerator getIdGenerator() { return idGenerator; } - - /** - * @param idGenerator the message ID generator to set - * @since Envoy v0.3-alpha - */ - public void setIdGenerator(IdGenerator idGenerator) { this.idGenerator = idGenerator; } - - /** - * @return {@code true} if an {@link IdGenerator} is present - * @since Envoy v0.3-alpha - */ - public boolean hasIdGenerator() { return idGenerator != null; } -} \ No newline at end of file diff --git a/src/main/java/envoy/client/database/LocalDb.java b/src/main/java/envoy/client/database/LocalDb.java new file mode 100644 index 0000000..58738e5 --- /dev/null +++ b/src/main/java/envoy/client/database/LocalDb.java @@ -0,0 +1,119 @@ +package envoy.client.database; + +import java.util.*; + +import envoy.client.Chat; +import envoy.data.IdGenerator; +import envoy.data.User; + +/** + * Stores information about the current {@link User} and their {@link Chat}s. + * For message ID generation a {@link IdGenerator} is stored as well.
+ *
+ * Project: envoy-client
+ * File: LocalDb.java
+ * Created: 3 Feb 2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public abstract class LocalDb { + + protected User user; + protected Map users = new HashMap<>(); + protected List chats = new ArrayList<>(); + protected IdGenerator idGenerator; + + /** + * Initializes a storage space for a user-specific list of chats. + * + * @since Envoy v0.3-alpha + */ + public void initializeUserStorage() {} + + /** + * Stores all users. If the client user is specified, their chats will be stored + * as well. The message id generator will also be saved if present. + * + * @throws Exception if the saving process failed + * @since Envoy v0.3-alpha + */ + public void save() throws Exception {} + + /** + * Loads all user data. + * + * @throws Exception if the loading process failed + * @since Envoy v0.3-alpha + */ + public void loadUsers() throws Exception {} + + /** + * Loads all chat data of the client user. + * + * @throws Exception if the loading process failed + * @since Envoy v0.3-alpha + */ + public void loadChats() throws Exception {} + + /** + * Loads the ID generator. Any exception thrown during this process is ignored. + * + * @since Envoy v0.3-alpha + */ + public void loadIdGenerator() {} + + /** + * @return a {@code Map} of all users stored locally with their + * user names as keys + * @since Envoy v0.2-alpha + */ + public Map getUsers() { return users; } + + /** + * @param users the users to set + */ + public void setUsers(Map users) { this.users = users; } + + /** + * @return all saved {@link Chat} objects that list the client user as the + * sender + * @since Envoy v0.1-alpha + **/ + public List getChats() { return chats; } + + /** + * @param chats the chats to set + */ + public void setChats(List chats) { this.chats = chats; } + + /** + * @return the {@link User} who initialized the local database + * @since Envoy v0.2-alpha + */ + public User getUser() { return user; } + + /** + * @param user the user to set + * @since Envoy v0.2-alpha + */ + public void setUser(User user) { this.user = user; } + + /** + * @return the message ID generator + * @since Envoy v0.3-alpha + */ + public IdGenerator getIdGenerator() { return idGenerator; } + + /** + * @param idGenerator the message ID generator to set + * @since Envoy v0.3-alpha + */ + public void setIdGenerator(IdGenerator idGenerator) { this.idGenerator = idGenerator; } + + /** + * @return {@code true} if an {@link IdGenerator} is present + * @since Envoy v0.3-alpha + */ + public boolean hasIdGenerator() { return idGenerator != null; } +} diff --git a/src/main/java/envoy/client/database/PersistentLocalDb.java b/src/main/java/envoy/client/database/PersistentLocalDb.java new file mode 100644 index 0000000..d4d7523 --- /dev/null +++ b/src/main/java/envoy/client/database/PersistentLocalDb.java @@ -0,0 +1,93 @@ +package envoy.client.database; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +import envoy.client.ConfigItem; +import envoy.data.IdGenerator; +import envoy.util.SerializationUtils; + +/** + * Implements a {@link LocalDb} in a way that stores all information inside a + * folder on the local file system.
+ *
+ * Project: envoy-client
+ * File: PersistentLocalDb.java
+ * Created: 27.10.2019
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.1-alpha + */ +public class PersistentLocalDb extends LocalDb { + + private File localDBDir, localDBFile, usersFile, idGeneratorFile; + + /** + * Initializes an empty local database without a directory. All changes made to + * this instance cannot be saved to the file system.
+ *
+ * This constructor shall be used in conjunction with the {@code ignoreLocalDB} + * {@link ConfigItem}. + * + * @since Envoy v0.3-alpha + */ + public PersistentLocalDb() {} + + /** + * Constructs an empty local database. To serialize any chats to the file + * system, call {@link PersistentLocalDb#initializeUserStorage()}. + * + * @param localDBDir the directory in which to store users and chats + * @throws IOException if the PersistentLocalDb could not be initialized + * @since Envoy v0.1-alpha + */ + public PersistentLocalDb(File localDBDir) throws IOException { + this.localDBDir = localDBDir; + + // Initialize local database directory + if (localDBDir.exists() && !localDBDir.isDirectory()) + throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); + usersFile = new File(localDBDir, "users.db"); + idGeneratorFile = new File(localDBDir, "id_generator.db"); + } + + /** + * Creates a database file for a user-specific list of chats. + * + * @throws NullPointerException if the client user is not yet specified + * @since Envoy v0.1-alpha + */ + @Override + public void initializeUserStorage() { + if (user == null) throw new NullPointerException("Client user is null"); + localDBFile = new File(localDBDir, user.getId() + ".db"); + } + + @Override + public void save() throws IOException { + // Save users + SerializationUtils.write(usersFile, users); + + // Save chats + if (user != null) SerializationUtils.write(localDBFile, chats); + + // Save id generator + if (hasIdGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator); + } + + @Override + public void loadUsers() throws ClassNotFoundException, IOException { users = SerializationUtils.read(usersFile, HashMap.class); } + + @Override + public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } + + @Override + public void loadIdGenerator() { + try { + idGenerator = SerializationUtils.read(idGeneratorFile, IdGenerator.class); + } catch (ClassNotFoundException | IOException e) {} + } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/database/TransientLocalDb.java b/src/main/java/envoy/client/database/TransientLocalDb.java new file mode 100644 index 0000000..f9124b1 --- /dev/null +++ b/src/main/java/envoy/client/database/TransientLocalDb.java @@ -0,0 +1,15 @@ +package envoy.client.database; + +/** + * Implements a {@link LocalDb} in a way that does not persist any information + * after application shutdown.
+ *
+ * Project: envoy-client
+ * File: TransientLocalDb.java
+ * Created: 3 Feb 2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class TransientLocalDb extends LocalDb { +} diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index ab9e968..1263a16 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -9,7 +9,10 @@ import java.util.logging.Logger; import javax.swing.*; import javax.swing.border.EmptyBorder; -import envoy.client.*; +import envoy.client.Chat; +import envoy.client.Client; +import envoy.client.Settings; +import envoy.client.database.LocalDb; import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.list.ComponentList; @@ -34,7 +37,7 @@ public class ChatWindow extends JFrame { // User specific objects private Client client; - private LocalDB localDB; + private LocalDb localDb; // GUI components private JPanel contentPane = new JPanel(); @@ -161,13 +164,13 @@ public class ChatWindow extends JFrame { userList.setCellRenderer(new UserListRenderer()); userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); userList.addListSelectionListener((listSelectionEvent) -> { - if (client != null && localDB != null && !listSelectionEvent.getValueIsAdjusting()) { + if (client != null && localDb != null && !listSelectionEvent.getValueIsAdjusting()) { @SuppressWarnings("unchecked") final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); // Select current chat - currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); + currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); // Read current Chat currentChat.read(); @@ -206,7 +209,7 @@ public class ChatWindow extends JFrame { // Listen to received messages EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { Message message = ((MessageCreationEvent) evt).get(); - localDB.getChats().stream().filter(c -> c.getRecipient().getId() == message.getSenderId()).findFirst().get().appendMessage(message); + localDb.getChats().stream().filter(c -> c.getRecipient().getId() == message.getSenderId()).findFirst().get().appendMessage(message); revalidate(); repaint(); }); @@ -262,7 +265,7 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { // Create message - final Message message = new MessageBuilder(localDB.getUser().getId(), currentChat.getRecipient().getId(), localDB.getIdGenerator()) + final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator()) .setText(messageEnterTextArea.getText()) .build(); @@ -270,7 +273,7 @@ public class ChatWindow extends JFrame { // TODO: Store offline messages client.sendMessage(message); - // Add message to LocalDB and update UI + // Add message to PersistentLocalDb and update UI currentChat.appendMessage(message); // messageList.setModel(currentChat.getModel()); @@ -281,8 +284,8 @@ public class ChatWindow extends JFrame { revalidate(); repaint(); - // Request a new id generator if all ids were used - if (!localDB.getIdGenerator().hasNext()) client.requestIdGenerator(); + // Request a new id generator if all IDs were used + if (!localDb.getIdGenerator().hasNext()) client.requestIdGenerator(); } catch (Exception e) { JOptionPane.showMessageDialog(this, @@ -302,12 +305,12 @@ public class ChatWindow extends JFrame { private void loadUsersAndChats() { new Thread(() -> { DefaultListModel userListModel = new DefaultListModel<>(); - localDB.getUsers().values().forEach(user -> { + localDb.getUsers().values().forEach(user -> { userListModel.addElement(user); // Check if user exists in local DB - if (localDB.getChats().stream().filter(c -> c.getRecipient().getId() == user.getId()).count() == 0) - localDB.getChats().add(new Chat(user)); + if (localDb.getChats().stream().filter(c -> c.getRecipient().getId() == user.getId()).count() == 0) + localDb.getChats().add(new Chat(user)); }); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); }).start(); @@ -324,14 +327,16 @@ public class ChatWindow extends JFrame { } /** - * Sets the {@link LocalDB} used by this {@link ChatWindow}. After invoking this + * Sets the {@link LocalDb} used by this {@link ChatWindow}. After + * invoking this * method, users and chats will be loaded from the database into the GUI. * - * @param localDB the {@link LocalDB} used to manage stored messages and users + * @param localDb the {@link LocalDb} used to manage stored messages + * and users * @since Envoy v0.2-alpha */ - public void setLocalDB(LocalDB localDB) { - this.localDB = localDB; + public void setLocalDB(LocalDb localDb) { + this.localDb = localDb; loadUsersAndChats(); } } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 949b464..0f564f8 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -11,7 +11,12 @@ import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; -import envoy.client.*; +import envoy.client.Client; +import envoy.client.Config; +import envoy.client.Settings; +import envoy.client.database.LocalDb; +import envoy.client.database.PersistentLocalDb; +import envoy.client.database.TransientLocalDb; import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; import envoy.data.User; @@ -63,8 +68,8 @@ public class Startup { } catch (Exception e) { JOptionPane .showMessageDialog(null, "Error loading configuration values:\n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE); - System.exit(1); e.printStackTrace(); + System.exit(1); } // Set new logger levels loaded from config @@ -80,12 +85,19 @@ public class Startup { } // Initialize the local database - LocalDB localDB; - try { - localDB = new LocalDB(new File(config.getHomeDirectory(), config.getLocalDB().getPath())); + LocalDb localDb; + if (config.isIgnoreLocalDB()) { + localDb = new TransientLocalDb(); + JOptionPane.showMessageDialog(null, + "Ignoring local database.\nMessages will not be saved!", + "Local database warning", + JOptionPane.WARNING_MESSAGE); + } else try { + localDb = new PersistentLocalDb(new File(config.getHomeDirectory(), config.getLocalDB().getPath())); } catch (IOException e3) { logger.log(Level.SEVERE, "Could not initialize local database", e3); - JOptionPane.showMessageDialog(null, "Could not initialize local database!\n" + e3.toString()); + JOptionPane + .showMessageDialog(null, "Could not initialize local database!\n" + e3.toString(), "Local database error", JOptionPane.ERROR_MESSAGE); System.exit(1); return; } @@ -97,15 +109,15 @@ public class Startup { Client client = new Client(); try { // Try entering online mode first - localDB.loadIdGenerator(); - client.onlineInit(credentials, localDB); + localDb.loadIdGenerator(); + client.onlineInit(credentials, localDb); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); e1.printStackTrace(); try { // Try entering offline mode - localDB.loadUsers(); - User clientUser = localDB.getUsers().get(credentials.getName()); + localDb.loadUsers(); + User clientUser = localDb.getUsers().get(credentials.getName()); if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); client.setSender(clientUser); JOptionPane.showMessageDialog(null, @@ -120,12 +132,12 @@ public class Startup { } // Set client user in local database - localDB.setUser(client.getSender()); + localDb.setUser(client.getSender()); // Initialize chats in local database try { - localDB.initializeDBFile(); - localDB.loadChats(); + localDb.initializeUserStorage(); + localDb.loadChats(); } catch (FileNotFoundException e) { // The local database file has not yet been created, probably first login } catch (Exception e) { @@ -137,12 +149,12 @@ public class Startup { } // Save all users to the local database - if (client.isOnline()) localDB.setUsers(client.getUsers()); + if (client.isOnline()) localDb.setUsers(client.getUsers()); EventQueue.invokeLater(() -> { try { chatWindow.setClient(client); - chatWindow.setLocalDB(localDB); + chatWindow.setLocalDB(localDb); try { new StatusTrayIcon(chatWindow).show(); @@ -162,16 +174,16 @@ public class Startup { } }); - // Save Settings and LocalDB on shutdown + // Save Settings and PersistentLocalDb on shutdown Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { logger.info("Closing connection..."); client.close(); logger.info("Saving local database and settings..."); - localDB.save(); + localDb.save(); Settings.getInstance().save(); - } catch (IOException e) { + } catch (Exception e) { logger.log(Level.SEVERE, "Unable to save local files", e); } })); From 89831f8aafc3ffc4ae9f29c80150650d9327e105 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 3 Feb 2020 22:06:56 +0100 Subject: [PATCH 207/474] Added Chat#isUnread() for future use in message notifications --- src/main/java/envoy/client/Chat.java | 7 +++++++ src/main/java/envoy/client/ui/list/ComponentListModel.java | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index b51f068..1a54e42 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -59,6 +59,13 @@ public class Chat implements Serializable { } } + /** + * @return {@code true} if the newest message received in the chat doesn't have + * the status {@code READ} + * @since Envoy v0.3-alpha + */ + public boolean isUnread() { return !model.isEmpty() && model.get(model.size() - 1).getStatus() != MessageStatus.READ; } + /** * @return all messages in the current chat * @since Envoy v0.1-alpha diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java index 8fb1d68..fff3e6c 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -78,6 +78,12 @@ public final class ComponentListModel implements Iterable, Serializable { */ public int size() { return elements.size(); } + /** + * @return {@code true} if this model contains no elements + * @see java.util.List#isEmpty() + */ + public boolean isEmpty() { return elements.isEmpty(); } + /** * @return an iterator over the elements of this list model * @see java.util.List#iterator() From 388987f438e9694a945f24a9ab34aebdaa38dcbc Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 4 Feb 2020 19:13:31 +0100 Subject: [PATCH 208/474] Implemented receiving unread messages using a message cache Fixes #98 --- src/main/java/envoy/client/Chat.java | 4 +- src/main/java/envoy/client/Client.java | 26 ++++++--- .../java/envoy/client/net/MessageCache.java | 54 +++++++++++++++++++ src/main/java/envoy/client/ui/Startup.java | 10 +++- 4 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 src/main/java/envoy/client/net/MessageCache.java diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index 1a54e42..b75175f 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -24,8 +24,8 @@ public class Chat implements Serializable { private static final long serialVersionUID = -7751248474547242056L; - private User recipient; - private ComponentListModel model = new ComponentListModel<>(); + private final User recipient; + private final ComponentListModel model = new ComponentListModel<>(); /** * Provides the list of messages that the recipient receives.
diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index a71f38e..145c1bb 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -10,6 +10,7 @@ import java.util.logging.Logger; import javax.naming.TimeLimitExceededException; import envoy.client.database.LocalDb; +import envoy.client.net.MessageCache; import envoy.client.net.ReceivedMessageProcessor; import envoy.client.net.Receiver; import envoy.client.util.EnvoyLog; @@ -48,14 +49,16 @@ public class Client implements Closeable { * will block for up to 5 seconds. If the handshake does exceed this time limit, * an exception is thrown. * - * @param credentials the login credentials of the user - * @param localDb the local database used to persist the current - * {@link IdGenerator} + * @param credentials the login credentials of the user + * @param localDb the local database used to persist the current + * {@link IdGenerator} + * @return a message cache containing all unread messages from the server that + * can be relayed after initialization * @throws Exception if the online mode could not be entered or the request * failed for some other reason * @since Envoy v0.2-alpha */ - public void onlineInit(LoginCredentials credentials, LocalDb localDb) throws Exception { + public MessageCache onlineInit(LoginCredentials credentials, LocalDb localDb) throws Exception { // Establish TCP connection logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); socket = new Socket(config.getServer(), config.getPort()); @@ -64,9 +67,13 @@ public class Client implements Closeable { // Create message receiver receiver = new Receiver(socket.getInputStream()); - // Register user creation processor + // Create cache for unread messages + final MessageCache cache = new MessageCache(); + + // Register user creation processor, contact list processor and message cache receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); receiver.registerProcessor(Contacts.class, contacts -> { logger.info("Acquired contacts object " + contacts); this.contacts = contacts; }); + receiver.registerProcessor(Message.class, cache); // Start receiver new Thread(receiver).start(); @@ -89,7 +96,12 @@ public class Client implements Closeable { receiver.removeAllProcessors(); // Register processors for message and status handling - receiver.registerProcessor(Message.class, new ReceivedMessageProcessor()); + final ReceivedMessageProcessor receivedMessageProcessor = new ReceivedMessageProcessor(); + receiver.registerProcessor(Message.class, receivedMessageProcessor); + + // Relay cached unread messages + cache.setProcessor(receivedMessageProcessor); + // TODO: Status handling // Process message ID generation @@ -97,6 +109,8 @@ public class Client implements Closeable { // Request a generator if none is present if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator(); + + return cache; } /** diff --git a/src/main/java/envoy/client/net/MessageCache.java b/src/main/java/envoy/client/net/MessageCache.java new file mode 100644 index 0000000..1fc49c3 --- /dev/null +++ b/src/main/java/envoy/client/net/MessageCache.java @@ -0,0 +1,54 @@ +package envoy.client.net; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import envoy.client.util.EnvoyLog; +import envoy.data.Message; + +/** + * Stores messages in a queue until the application initialization is complete. + * The messages can then be relayed to a processor.
+ *
+ * Project: envoy-client
+ * File: MessageCache.java
+ * Created: 4 Feb 2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class MessageCache implements Consumer { + + private final Queue messages = new LinkedList<>(); + private Consumer processor; + + private static final Logger logger = EnvoyLog.getLogger(MessageCache.class.getSimpleName()); + + /** + * Adds a message to the cache. + * + * @since Envoy v0.3-alpha + */ + @Override + public void accept(Message message) { + logger.info(String.format("Adding message %s to cache", message)); + messages.add(message); + } + + /** + * Sets the processor to which messages are relayed. + * + * @param processor the processor to set + * @since Envoy v0.3-alpha + */ + public void setProcessor(Consumer processor) { this.processor = processor; } + + /** + * Relays all cached messages to the processor. + * + * @since Envoy v0.3-alpha + */ + public void relayMessages() { messages.forEach(processor::accept); } +} diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 0f564f8..1bdbe73 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -17,6 +17,7 @@ import envoy.client.Settings; import envoy.client.database.LocalDb; import envoy.client.database.PersistentLocalDb; import envoy.client.database.TransientLocalDb; +import envoy.client.net.MessageCache; import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; import envoy.data.User; @@ -106,11 +107,12 @@ public class Startup { // Acquire the client user (with ID) either from the server or from the local // database, which triggers offline mode - Client client = new Client(); + Client client = new Client(); + MessageCache cache = null; try { // Try entering online mode first localDb.loadIdGenerator(); - client.onlineInit(credentials, localDb); + cache = client.onlineInit(credentials, localDb); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); e1.printStackTrace(); @@ -151,6 +153,7 @@ public class Startup { // Save all users to the local database if (client.isOnline()) localDb.setUsers(client.getUsers()); + // Display ChatWindow and StatusTrayIcon EventQueue.invokeLater(() -> { try { chatWindow.setClient(client); @@ -174,6 +177,9 @@ public class Startup { } }); + // Relay unread messages from cache + if (cache != null) cache.relayMessages(); + // Save Settings and PersistentLocalDb on shutdown Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { From 7424cc900fda31ca60f5fa5ee0944b141cf36e07 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 4 Feb 2020 19:46:18 +0100 Subject: [PATCH 209/474] Moved client to net package, removed unnecessary recipient property --- .../java/envoy/client/{ => net}/Client.java | 41 +++++-------------- src/main/java/envoy/client/ui/ChatWindow.java | 8 ++-- src/main/java/envoy/client/ui/Startup.java | 2 +- 3 files changed, 15 insertions(+), 36 deletions(-) rename src/main/java/envoy/client/{ => net}/Client.java (88%) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/net/Client.java similarity index 88% rename from src/main/java/envoy/client/Client.java rename to src/main/java/envoy/client/net/Client.java index 145c1bb..0920aab 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -1,4 +1,4 @@ -package envoy.client; +package envoy.client.net; import java.io.Closeable; import java.io.IOException; @@ -9,16 +9,17 @@ import java.util.logging.Logger; import javax.naming.TimeLimitExceededException; +import envoy.client.Config; import envoy.client.database.LocalDb; -import envoy.client.net.MessageCache; -import envoy.client.net.ReceivedMessageProcessor; -import envoy.client.net.Receiver; import envoy.client.util.EnvoyLog; import envoy.data.*; import envoy.event.IdGeneratorRequest; import envoy.util.SerializationUtils; /** + * Establishes a connection to the server, performs a handshake and delivers + * certain objects to the server.
+ *
* Project: envoy-client
* File: Client.java
* Created: 28 Sep 2019
@@ -30,17 +31,17 @@ import envoy.util.SerializationUtils; */ public class Client implements Closeable { + // Connection handling private Socket socket; private Receiver receiver; private boolean online; - private volatile User sender; - private User recipient; - - private volatile Contacts contacts; - - private Config config = Config.getInstance(); + // Asynchronously initialized during handshake + private volatile User sender; + private volatile Contacts contacts; + // Configuration and logging + private static final Config config = Config.getInstance(); private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); /** @@ -172,26 +173,6 @@ public class Client implements Closeable { */ public void setSender(User sender) { this.sender = sender; } - /** - * @return the current recipient of the current chat. - * @since Envoy v0.1-alpha - */ - public User getRecipient() { return recipient; } - - /** - * Sets the recipient. - * - * @param recipient the recipient to set - * @since Envoy v0.1-alpha - */ - public void setRecipient(User recipient) { this.recipient = recipient; } - - /** - * @return true, if a recipient is selected - * @since Envoy v0.1-alpha - */ - public boolean hasRecipient() { return recipient != null; } - /** * @return the {@link Receiver} used by this {@link Client} */ diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 1263a16..b92446a 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -10,11 +10,11 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; import envoy.client.Chat; -import envoy.client.Client; import envoy.client.Settings; import envoy.client.database.LocalDb; import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; +import envoy.client.net.Client; import envoy.client.ui.list.ComponentList; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; @@ -175,8 +175,7 @@ public class ChatWindow extends JFrame { // Read current Chat currentChat.read(); - // Set recipient in client and chat title - client.setRecipient(user); + // Set chat title textPane.setText(currentChat.getRecipient().getName()); // Update model and scroll down @@ -257,7 +256,7 @@ public class ChatWindow extends JFrame { } private void postMessage() { - if (!client.hasRecipient()) { + if (userList.isSelectionEmpty()) { JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); return; } @@ -275,7 +274,6 @@ public class ChatWindow extends JFrame { // Add message to PersistentLocalDb and update UI currentChat.appendMessage(message); - // messageList.setModel(currentChat.getModel()); // Clear text field messageEnterTextArea.setText(""); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 1bdbe73..272e1ec 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -11,12 +11,12 @@ import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; -import envoy.client.Client; import envoy.client.Config; import envoy.client.Settings; import envoy.client.database.LocalDb; import envoy.client.database.PersistentLocalDb; import envoy.client.database.TransientLocalDb; +import envoy.client.net.Client; import envoy.client.net.MessageCache; import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; From b6167ce166e11ba58106fe33ce9ffb329ff1bd31 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 5 Feb 2020 07:09:25 +0100 Subject: [PATCH 210/474] Listening to message status changes, sending READ status updates --- src/main/java/envoy/client/Chat.java | 24 +++++++++--- src/main/java/envoy/client/net/Client.java | 20 ++++++++-- .../MessageStatusChangeEventProcessor.java | 38 ++++++++++++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 39 +++++++++++++++---- 4 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index b75175f..e67eb34 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -1,11 +1,14 @@ package envoy.client; +import java.io.IOException; import java.io.Serializable; +import envoy.client.net.Client; import envoy.client.ui.list.ComponentListModel; import envoy.data.Message; import envoy.data.Message.MessageStatus; import envoy.data.User; +import envoy.event.MessageStatusChangeEvent; /** * Represents a chat between two {@link User}s
@@ -49,14 +52,25 @@ public class Chat implements Serializable { * {@code READ} starting from the bottom and stopping once a read message is * found. * + * @param client the client instance used to notify the server about the message + * status changes + * @throws IOException if a {@link MessageStatusChangeEvent} could not be + * delivered to the server * @since Envoy v0.3-alpha */ - public void read() { - for (int i = model.size() - 1; i >= 0; --i) - if (model.get(i).getSenderId() == recipient.getId()) { - if (model.get(i).getStatus() == MessageStatus.READ) break; - else model.get(i).setStatus(MessageStatus.READ); + public void read(Client client) throws IOException { + for (int i = model.size() - 1; i >= 0; --i) { + final Message m = model.get(i); + if (m.getSenderId() == recipient.getId()) { + if (m.getStatus() == MessageStatus.READ) break; + else { + m.setStatus(MessageStatus.READ); + + // TODO: Cache events in offline mode + client.sendEvent(new MessageStatusChangeEvent(m)); + } } + } } /** diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 0920aab..31b1d59 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -13,7 +13,9 @@ import envoy.client.Config; import envoy.client.database.LocalDb; import envoy.client.util.EnvoyLog; import envoy.data.*; +import envoy.event.Event; import envoy.event.IdGeneratorRequest; +import envoy.event.MessageStatusChangeEvent; import envoy.util.SerializationUtils; /** @@ -42,7 +44,7 @@ public class Client implements Closeable { // Configuration and logging private static final Config config = Config.getInstance(); - private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); /** * Enters the online mode by acquiring a user ID from the server. As a @@ -103,19 +105,21 @@ public class Client implements Closeable { // Relay cached unread messages cache.setProcessor(receivedMessageProcessor); - // TODO: Status handling + // Process message status changes + receiver.registerProcessor(MessageStatusChangeEvent.class, new MessageStatusChangeEventProcessor()); // Process message ID generation receiver.registerProcessor(IdGenerator.class, localDb::setIdGenerator); - // Request a generator if none is present + // Request a generator if none is present or the existing one is consumed if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator(); return cache; } /** - * Sends a message to the server. + * Sends a message to the server. The message's status will be incremented once + * it was delivered successfully. * * @param message the message to send * @throws IOException if the message does not reach the server @@ -126,6 +130,14 @@ public class Client implements Closeable { message.nextStatus(); } + /** + * Sends an event to the server. + * + * @param evt the event to send + * @throws IOException if the event did not reach the server + */ + public void sendEvent(Event evt) throws IOException { writeObject(evt); } + /** * Requests a new {@link IdGenerator} from the server. * diff --git a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java new file mode 100644 index 0000000..1ceecf1 --- /dev/null +++ b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java @@ -0,0 +1,38 @@ +package envoy.client.net; + +import java.util.function.Consumer; +import java.util.logging.Logger; + +import envoy.client.util.EnvoyLog; +import envoy.data.Message.MessageStatus; +import envoy.event.EventBus; +import envoy.event.MessageStatusChangeEvent; + +/** + * Project: envoy-client
+ * File: MessageStatusChangeEventProcessor.java
+ * Created: 4 Feb 2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class MessageStatusChangeEventProcessor implements Consumer { + + private static final Logger logger = EnvoyLog.getLogger(MessageStatusChangeEventProcessor.class.getSimpleName()); + + /** + * Dispatches a {@link MessageStatusChangeEvent} if the status is + * {@code RECEIVED} or {@code READ}. + * + * @param evt the status change event + * @since Envoy v0.3-alpha + */ + @Override + public void accept(MessageStatusChangeEvent evt) { + if (evt.get().ordinal() <= MessageStatus.RECEIVED.ordinal()) logger.info("Received invalid message status change " + evt); + else { + logger.info("Received " + evt.toString()); + EventBus.getInstance().dispatch(evt); + } + } +} diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index b92446a..aba5726 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -3,6 +3,7 @@ package envoy.client.ui; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -19,9 +20,11 @@ import envoy.client.ui.list.ComponentList; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; import envoy.data.Message; +import envoy.data.Message.MessageStatus; import envoy.data.MessageBuilder; import envoy.data.User; import envoy.event.EventBus; +import envoy.event.MessageStatusChangeEvent; /** * Project: envoy-client
@@ -173,7 +176,12 @@ public class ChatWindow extends JFrame { currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); // Read current Chat - currentChat.read(); + try { + currentChat.read(client); + } catch (IOException e) { + e.printStackTrace(); + logger.log(Level.WARNING, "Could notify server about message status change", e); + } // Set chat title textPane.setText(currentChat.getRecipient().getName()); @@ -213,6 +221,26 @@ public class ChatWindow extends JFrame { repaint(); }); + // Listen to message status changes + EventBus.getInstance().register(MessageStatusChangeEvent.class, (evt) -> { + final long id = ((MessageStatusChangeEvent) evt).getId(); + final MessageStatus status = (MessageStatus) evt.get(); + + for (Chat c : localDb.getChats()) + for (Message m : c.getModel()) + if (m.getId() == id) { + + // Update message status + m.setStatus(status); + + // Update model and scroll down if current chat + if (c == currentChat) { + messageList.setModel(currentChat.getModel()); + scrollPane.setChatOpened(true); + } + } + }); + revalidate(); } @@ -286,10 +314,7 @@ public class ChatWindow extends JFrame { if (!localDb.getIdGenerator().hasNext()) client.requestIdGenerator(); } catch (Exception e) { - JOptionPane.showMessageDialog(this, - "Error sending message:\n" + e.toString(), - "Message sending error", - JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this, "Error sending message:\n" + e.toString(), "Message sending error", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } @@ -320,9 +345,7 @@ public class ChatWindow extends JFrame { * @param client the {@link Client} used to send and receive messages * @since Envoy v0.2-alpha */ - public void setClient(Client client) { - this.client = client; - } + public void setClient(Client client) { this.client = client; } /** * Sets the {@link LocalDb} used by this {@link ChatWindow}. After From 7d7dd02ceb87435143fcb55d8eb52152a082b94c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 5 Feb 2020 16:12:10 +0100 Subject: [PATCH 211/474] Updating status of received messages to RECEIVED --- .../java/envoy/client/net/ReceivedMessageProcessor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/net/ReceivedMessageProcessor.java b/src/main/java/envoy/client/net/ReceivedMessageProcessor.java index 27b505e..ba0a386 100644 --- a/src/main/java/envoy/client/net/ReceivedMessageProcessor.java +++ b/src/main/java/envoy/client/net/ReceivedMessageProcessor.java @@ -25,8 +25,12 @@ public class ReceivedMessageProcessor implements Consumer { public void accept(Message message) { logger.info("Received message object " + message); if (message.getStatus() != MessageStatus.SENT) logger.warning("The message has the unexpected status " + message.getStatus()); - else + else { + // Update status to RECEIVED + message.nextStatus(); + // Dispatch event EventBus.getInstance().dispatch(new MessageCreationEvent(message)); + } } } From 9e024ede099be3c46539002f904ea5ea68b8d88e Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Wed, 5 Feb 2020 17:23:30 +0100 Subject: [PATCH 212/474] Reading current chat when a new message is received --- .../MessageStatusChangeEventProcessor.java | 2 +- src/main/java/envoy/client/ui/ChatWindow.java | 15 +++++++++++- .../envoy/client/ui/list/ComponentList.java | 24 +++++++++---------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java index 1ceecf1..1cf457f 100644 --- a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java +++ b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java @@ -29,7 +29,7 @@ public class MessageStatusChangeEventProcessor implements Consumer { Message message = ((MessageCreationEvent) evt).get(); - localDb.getChats().stream().filter(c -> c.getRecipient().getId() == message.getSenderId()).findFirst().get().appendMessage(message); + Chat chat = localDb.getChats().stream().filter(c -> c.getRecipient().getId() == message.getSenderId()).findFirst().get(); + chat.appendMessage(message); + + // Read message and update UI if in current chat + if (chat == currentChat) { + try { + currentChat.read(client); + } catch (IOException e) { + e.printStackTrace(); + logger.log(Level.WARNING, "Could notify server about message status change", e); + } + messageList.synchronizeModel(); + } + revalidate(); repaint(); }); diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 8cbf2db..f62dc7b 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -66,6 +66,18 @@ public class ComponentList extends JPanel { synchronizeModel(); } + /** + * Removes all child components and then adds all components representing the + * elements of the {@link ComponentListModel}. + * + * @since Envoy v0.3-alpha + */ + public void synchronizeModel() { + removeAll(); + if (model != null) for (E elem : model) + add(elem); + } + /** * Adds an object to the list by rendering it with the current * {@link ComponentListCellRenderer}. @@ -76,16 +88,4 @@ public class ComponentList extends JPanel { void add(E elem) { add(renderer.getListCellComponent(this, elem, false)); } - - /** - * Removes all child components and then adds all components representing the - * elements of the {@link ComponentListModel}. - * - * @since Envoy v0.3-alpha - */ - void synchronizeModel() { - removeAll(); - if (model != null) for (E elem : model) - add(elem); - } } From 19fafc4c38c06159377b218c29235670366b4809 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 5 Feb 2020 20:08:24 +0100 Subject: [PATCH 213/474] Fixed UI update after message status changes --- src/main/java/envoy/client/event/MessageCreationEvent.java | 1 + src/main/java/envoy/client/event/MessageEvent.java | 1 + .../java/envoy/client/event/MessageModificationEvent.java | 1 + src/main/java/envoy/client/ui/ChatWindow.java | 6 +++++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java index 301603e..72e47f5 100644 --- a/src/main/java/envoy/client/event/MessageCreationEvent.java +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -8,6 +8,7 @@ import envoy.data.Message; * Created: 4 Dec 2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public class MessageCreationEvent extends MessageEvent { diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java index 8bd05d1..fb50109 100644 --- a/src/main/java/envoy/client/event/MessageEvent.java +++ b/src/main/java/envoy/client/event/MessageEvent.java @@ -9,6 +9,7 @@ import envoy.event.Event; * Created: 4 Dec 2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public class MessageEvent implements Event { diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java index 3a5549a..4077383 100644 --- a/src/main/java/envoy/client/event/MessageModificationEvent.java +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -8,6 +8,7 @@ import envoy.data.Message; * Created: 4 Dec 2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public class MessageModificationEvent extends MessageEvent { diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 81d04f6..d018b40 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -190,6 +190,7 @@ public class ChatWindow extends JFrame { messageList.setModel(currentChat.getModel()); scrollPane.setChatOpened(true); + messageList.synchronizeModel(); revalidate(); repaint(); } @@ -250,8 +251,11 @@ public class ChatWindow extends JFrame { if (c == currentChat) { messageList.setModel(currentChat.getModel()); scrollPane.setChatOpened(true); - } + } else messageList.synchronizeModel(); } + + revalidate(); + repaint(); }); revalidate(); From f80fd5069c3c022f197b93a343d9f4f092fc8cf1 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 5 Feb 2020 20:58:30 +0100 Subject: [PATCH 214/474] Renamed database package to data, moved Chat to data package --- .../java/envoy/client/{ => data}/Chat.java | 2 +- .../client/{database => data}/LocalDb.java | 3 +- .../{database => data}/PersistentLocalDb.java | 2 +- .../{database => data}/TransientLocalDb.java | 2 +- src/main/java/envoy/client/net/Client.java | 2 +- src/main/java/envoy/client/ui/ChatWindow.java | 33 +++++++++---------- src/main/java/envoy/client/ui/Startup.java | 6 ++-- 7 files changed, 23 insertions(+), 27 deletions(-) rename src/main/java/envoy/client/{ => data}/Chat.java (99%) rename src/main/java/envoy/client/{database => data}/LocalDb.java (98%) rename src/main/java/envoy/client/{database => data}/PersistentLocalDb.java (98%) rename src/main/java/envoy/client/{database => data}/TransientLocalDb.java (92%) diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/data/Chat.java similarity index 99% rename from src/main/java/envoy/client/Chat.java rename to src/main/java/envoy/client/data/Chat.java index e67eb34..f10e816 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/data/Chat.java @@ -1,4 +1,4 @@ -package envoy.client; +package envoy.client.data; import java.io.IOException; import java.io.Serializable; diff --git a/src/main/java/envoy/client/database/LocalDb.java b/src/main/java/envoy/client/data/LocalDb.java similarity index 98% rename from src/main/java/envoy/client/database/LocalDb.java rename to src/main/java/envoy/client/data/LocalDb.java index 58738e5..79368a8 100644 --- a/src/main/java/envoy/client/database/LocalDb.java +++ b/src/main/java/envoy/client/data/LocalDb.java @@ -1,8 +1,7 @@ -package envoy.client.database; +package envoy.client.data; import java.util.*; -import envoy.client.Chat; import envoy.data.IdGenerator; import envoy.data.User; diff --git a/src/main/java/envoy/client/database/PersistentLocalDb.java b/src/main/java/envoy/client/data/PersistentLocalDb.java similarity index 98% rename from src/main/java/envoy/client/database/PersistentLocalDb.java rename to src/main/java/envoy/client/data/PersistentLocalDb.java index d4d7523..7856517 100644 --- a/src/main/java/envoy/client/database/PersistentLocalDb.java +++ b/src/main/java/envoy/client/data/PersistentLocalDb.java @@ -1,4 +1,4 @@ -package envoy.client.database; +package envoy.client.data; import java.io.File; import java.io.IOException; diff --git a/src/main/java/envoy/client/database/TransientLocalDb.java b/src/main/java/envoy/client/data/TransientLocalDb.java similarity index 92% rename from src/main/java/envoy/client/database/TransientLocalDb.java rename to src/main/java/envoy/client/data/TransientLocalDb.java index f9124b1..433488a 100644 --- a/src/main/java/envoy/client/database/TransientLocalDb.java +++ b/src/main/java/envoy/client/data/TransientLocalDb.java @@ -1,4 +1,4 @@ -package envoy.client.database; +package envoy.client.data; /** * Implements a {@link LocalDb} in a way that does not persist any information diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 31b1d59..91e9040 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -10,7 +10,7 @@ import java.util.logging.Logger; import javax.naming.TimeLimitExceededException; import envoy.client.Config; -import envoy.client.database.LocalDb; +import envoy.client.data.LocalDb; import envoy.client.util.EnvoyLog; import envoy.data.*; import envoy.event.Event; diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index d018b40..3abd54a 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -10,9 +10,9 @@ import java.util.logging.Logger; import javax.swing.*; import javax.swing.border.EmptyBorder; -import envoy.client.Chat; import envoy.client.Settings; -import envoy.client.database.LocalDb; +import envoy.client.data.Chat; +import envoy.client.data.LocalDb; import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.net.Client; @@ -175,13 +175,8 @@ public class ChatWindow extends JFrame { // Select current chat currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); - // Read current Chat - try { - currentChat.read(client); - } catch (IOException e) { - e.printStackTrace(); - logger.log(Level.WARNING, "Could notify server about message status change", e); - } + // Read current chat + readCurrentChat(); // Set chat title textPane.setText(currentChat.getRecipient().getName()); @@ -221,15 +216,7 @@ public class ChatWindow extends JFrame { chat.appendMessage(message); // Read message and update UI if in current chat - if (chat == currentChat) { - try { - currentChat.read(client); - } catch (IOException e) { - e.printStackTrace(); - logger.log(Level.WARNING, "Could notify server about message status change", e); - } - messageList.synchronizeModel(); - } + if (chat == currentChat) readCurrentChat(); revalidate(); repaint(); @@ -356,6 +343,16 @@ public class ChatWindow extends JFrame { }).start(); } + private void readCurrentChat() { + try { + currentChat.read(client); + messageList.synchronizeModel(); + } catch (IOException e) { + e.printStackTrace(); + logger.log(Level.WARNING, "Couldn't notify server about message status change", e); + } + } + /** * Sets the {@link Client} used by this {@link ChatWindow}. * diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 272e1ec..9f308dc 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -13,9 +13,9 @@ import javax.swing.SwingUtilities; import envoy.client.Config; import envoy.client.Settings; -import envoy.client.database.LocalDb; -import envoy.client.database.PersistentLocalDb; -import envoy.client.database.TransientLocalDb; +import envoy.client.data.LocalDb; +import envoy.client.data.PersistentLocalDb; +import envoy.client.data.TransientLocalDb; import envoy.client.net.Client; import envoy.client.net.MessageCache; import envoy.client.util.EnvoyLog; From 762ec8b2b4c51f949dc44f9064394a482120dce2 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Wed, 5 Feb 2020 21:02:36 +0100 Subject: [PATCH 215/474] Update README.md Added breaks fixes #76 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c52e7fd..c451b13 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ **Envoy Client** is one of two repositories needed to use the messenger Envoy.
The other one is **Envoy Common**.
In the future, Envoy Common might be discarded, but for now, both Repositories are required in order to use Envoy to send messages to other people.
-

+




## Features From 17391767997676c1f65725a8e6555d9470dc88a2 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 5 Feb 2020 21:53:39 +0100 Subject: [PATCH 216/474] Added assembly plugin configuration for JAR packaging to pom.xml --- pom.xml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/pom.xml b/pom.xml index 0b5487d..ec25577 100644 --- a/pom.xml +++ b/pom.xml @@ -39,5 +39,30 @@ src/main/resources + + + org.apache.maven.plugins + maven-assembly-plugin + 2.4.1 + + + package + + single + + + + + envoy.client.ui.Startup + + + + jar-with-dependencies + + + + + + \ No newline at end of file From 6bbd6936e09bc405ae021a030900de5daf5fb523 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 6 Feb 2020 18:35:05 +0100 Subject: [PATCH 217/474] Replaced MessageCache by Cache This class will be used to implement the offline cache for both messages and events. --- src/main/java/envoy/client/data/Cache.java | 58 +++++++++++++++++++ src/main/java/envoy/client/net/Client.java | 5 +- .../java/envoy/client/net/MessageCache.java | 54 ----------------- src/main/java/envoy/client/ui/Startup.java | 10 ++-- 4 files changed, 65 insertions(+), 62 deletions(-) create mode 100644 src/main/java/envoy/client/data/Cache.java delete mode 100644 src/main/java/envoy/client/net/MessageCache.java diff --git a/src/main/java/envoy/client/data/Cache.java b/src/main/java/envoy/client/data/Cache.java new file mode 100644 index 0000000..366f703 --- /dev/null +++ b/src/main/java/envoy/client/data/Cache.java @@ -0,0 +1,58 @@ +package envoy.client.data; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import envoy.client.util.EnvoyLog; + +/** + * Stores elements in a queue to process them later.
+ *
+ * Project: envoy-client
+ * File: Cache.java
+ * Created: 6 Feb 2020
+ * + * @param the type of cached elements + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class Cache implements Consumer { + + private final Queue elements = new LinkedList<>(); + private Consumer processor; + + private static final Logger logger = EnvoyLog.getLogger(Cache.class.getSimpleName()); + + /** + * Adds an element to the cache. + * + * @param element the element to add + * @since Envoy v0.3-alpha + */ + @Override + public void accept(T element) { + logger.info(String.format("Adding element %s to cache", element)); + elements.offer(element); + } + + /** + * Sets the processor to which cached elements are relayed. + * + * @param processor the processor to set + * @since Envoy v0.3-alpha + */ + public void setProcessor(Consumer processor) { this.processor = processor; } + + /** + * Relays all cached elements to the processor. + * + * @throws IllegalStateException if the processor is not initialized + * @since Envoy v0.3-alpha + */ + public void relay() { + if (processor == null) throw new IllegalStateException("Processor is not defined"); + elements.forEach(processor::accept); + } +} diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 91e9040..2e96b4a 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -10,6 +10,7 @@ import java.util.logging.Logger; import javax.naming.TimeLimitExceededException; import envoy.client.Config; +import envoy.client.data.Cache; import envoy.client.data.LocalDb; import envoy.client.util.EnvoyLog; import envoy.data.*; @@ -61,7 +62,7 @@ public class Client implements Closeable { * failed for some other reason * @since Envoy v0.2-alpha */ - public MessageCache onlineInit(LoginCredentials credentials, LocalDb localDb) throws Exception { + public Cache onlineInit(LoginCredentials credentials, LocalDb localDb) throws Exception { // Establish TCP connection logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); socket = new Socket(config.getServer(), config.getPort()); @@ -71,7 +72,7 @@ public class Client implements Closeable { receiver = new Receiver(socket.getInputStream()); // Create cache for unread messages - final MessageCache cache = new MessageCache(); + final Cache cache = new Cache<>(); // Register user creation processor, contact list processor and message cache receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); diff --git a/src/main/java/envoy/client/net/MessageCache.java b/src/main/java/envoy/client/net/MessageCache.java deleted file mode 100644 index 1fc49c3..0000000 --- a/src/main/java/envoy/client/net/MessageCache.java +++ /dev/null @@ -1,54 +0,0 @@ -package envoy.client.net; - -import java.util.LinkedList; -import java.util.Queue; -import java.util.function.Consumer; -import java.util.logging.Logger; - -import envoy.client.util.EnvoyLog; -import envoy.data.Message; - -/** - * Stores messages in a queue until the application initialization is complete. - * The messages can then be relayed to a processor.
- *
- * Project: envoy-client
- * File: MessageCache.java
- * Created: 4 Feb 2020
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha - */ -public class MessageCache implements Consumer { - - private final Queue messages = new LinkedList<>(); - private Consumer processor; - - private static final Logger logger = EnvoyLog.getLogger(MessageCache.class.getSimpleName()); - - /** - * Adds a message to the cache. - * - * @since Envoy v0.3-alpha - */ - @Override - public void accept(Message message) { - logger.info(String.format("Adding message %s to cache", message)); - messages.add(message); - } - - /** - * Sets the processor to which messages are relayed. - * - * @param processor the processor to set - * @since Envoy v0.3-alpha - */ - public void setProcessor(Consumer processor) { this.processor = processor; } - - /** - * Relays all cached messages to the processor. - * - * @since Envoy v0.3-alpha - */ - public void relayMessages() { messages.forEach(processor::accept); } -} diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 9f308dc..1a38da9 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -13,13 +13,11 @@ import javax.swing.SwingUtilities; import envoy.client.Config; import envoy.client.Settings; -import envoy.client.data.LocalDb; -import envoy.client.data.PersistentLocalDb; -import envoy.client.data.TransientLocalDb; +import envoy.client.data.*; import envoy.client.net.Client; -import envoy.client.net.MessageCache; import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; +import envoy.data.Message; import envoy.data.User; import envoy.exception.EnvoyException; @@ -108,7 +106,7 @@ public class Startup { // Acquire the client user (with ID) either from the server or from the local // database, which triggers offline mode Client client = new Client(); - MessageCache cache = null; + Cache cache = null; try { // Try entering online mode first localDb.loadIdGenerator(); @@ -178,7 +176,7 @@ public class Startup { }); // Relay unread messages from cache - if (cache != null) cache.relayMessages(); + if (cache != null) cache.relay(); // Save Settings and PersistentLocalDb on shutdown Runtime.getRuntime().addShutdownHook(new Thread(() -> { From 0646445d3c4363dbade5faabd70fa50392a5dde0 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 6 Feb 2020 21:03:08 +0100 Subject: [PATCH 218/474] Added WriteProxy with creation method in Client, added caches to LocalDb --- src/main/java/envoy/client/data/Cache.java | 5 +- src/main/java/envoy/client/data/LocalDb.java | 36 ++++++- .../envoy/client/data/PersistentLocalDb.java | 14 +-- src/main/java/envoy/client/net/Client.java | 11 ++ .../java/envoy/client/net/WriteProxy.java | 102 ++++++++++++++++++ 5 files changed, 155 insertions(+), 13 deletions(-) create mode 100644 src/main/java/envoy/client/net/WriteProxy.java diff --git a/src/main/java/envoy/client/data/Cache.java b/src/main/java/envoy/client/data/Cache.java index 366f703..458cb0a 100644 --- a/src/main/java/envoy/client/data/Cache.java +++ b/src/main/java/envoy/client/data/Cache.java @@ -20,8 +20,8 @@ import envoy.client.util.EnvoyLog; */ public class Cache implements Consumer { - private final Queue elements = new LinkedList<>(); - private Consumer processor; + private final Queue elements = new LinkedList<>(); + private transient Consumer processor; private static final Logger logger = EnvoyLog.getLogger(Cache.class.getSimpleName()); @@ -54,5 +54,6 @@ public class Cache implements Consumer { public void relay() { if (processor == null) throw new IllegalStateException("Processor is not defined"); elements.forEach(processor::accept); + elements.clear(); } } diff --git a/src/main/java/envoy/client/data/LocalDb.java b/src/main/java/envoy/client/data/LocalDb.java index 79368a8..a606856 100644 --- a/src/main/java/envoy/client/data/LocalDb.java +++ b/src/main/java/envoy/client/data/LocalDb.java @@ -3,7 +3,9 @@ package envoy.client.data; import java.util.*; import envoy.data.IdGenerator; +import envoy.data.Message; import envoy.data.User; +import envoy.event.MessageStatusChangeEvent; /** * Stores information about the current {@link User} and their {@link Chat}s. @@ -18,10 +20,12 @@ import envoy.data.User; */ public abstract class LocalDb { - protected User user; - protected Map users = new HashMap<>(); - protected List chats = new ArrayList<>(); - protected IdGenerator idGenerator; + protected User user; + protected Map users = new HashMap<>(); + protected List chats = new ArrayList<>(); + protected IdGenerator idGenerator; + protected Cache messageCache; + protected Cache statusCache; /** * Initializes a storage space for a user-specific list of chats. @@ -115,4 +119,28 @@ public abstract class LocalDb { * @since Envoy v0.3-alpha */ public boolean hasIdGenerator() { return idGenerator != null; } + + /** + * @return the offline message cache + * @since Envoy v0.3-alpha + */ + public Cache getMessageCache() { return messageCache; } + + /** + * @param messageCache the offline message cache to set + * @since Envoy v0.3-alpha + */ + public void setMessageCache(Cache messageCache) { this.messageCache = messageCache; } + + /** + * @return the offline status cache + * @since Envoy v0.3-alpha + */ + public Cache getStatusCache() { return statusCache; } + + /** + * @param statusCache the offline status cache to set + * @since Envoy v0.3-alpha + */ + public void setStatusCache(Cache statusCache) { this.statusCache = statusCache; } } diff --git a/src/main/java/envoy/client/data/PersistentLocalDb.java b/src/main/java/envoy/client/data/PersistentLocalDb.java index 7856517..7052c60 100644 --- a/src/main/java/envoy/client/data/PersistentLocalDb.java +++ b/src/main/java/envoy/client/data/PersistentLocalDb.java @@ -40,18 +40,18 @@ public class PersistentLocalDb extends LocalDb { * Constructs an empty local database. To serialize any chats to the file * system, call {@link PersistentLocalDb#initializeUserStorage()}. * - * @param localDBDir the directory in which to store users and chats + * @param localDbDir the directory in which to store users and chats * @throws IOException if the PersistentLocalDb could not be initialized * @since Envoy v0.1-alpha */ - public PersistentLocalDb(File localDBDir) throws IOException { - this.localDBDir = localDBDir; + public PersistentLocalDb(File localDbDir) throws IOException { + localDBDir = localDbDir; // Initialize local database directory - if (localDBDir.exists() && !localDBDir.isDirectory()) - throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - usersFile = new File(localDBDir, "users.db"); - idGeneratorFile = new File(localDBDir, "id_generator.db"); + if (localDbDir.exists() && !localDbDir.isDirectory()) + throw new IOException(String.format("LocalDbDir '%s' is not a directory!", localDbDir.getAbsolutePath())); + usersFile = new File(localDbDir, "users.db"); + idGeneratorFile = new File(localDbDir, "id_generator.db"); } /** diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 2e96b4a..29b2f03 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -118,6 +118,17 @@ public class Client implements Closeable { return cache; } + /** + * Creates a new write proxy that uses this client to communicate with the + * server. + * + * @param localDb the local database that the write proxy will use to access + * caches + * @return a new write proxy + * @since Envoy Client v0.3-alpha + */ + public WriteProxy createWriteProxy(LocalDb localDb) { return new WriteProxy(this, localDb); } + /** * Sends a message to the server. The message's status will be incremented once * it was delivered successfully. diff --git a/src/main/java/envoy/client/net/WriteProxy.java b/src/main/java/envoy/client/net/WriteProxy.java new file mode 100644 index 0000000..454751f --- /dev/null +++ b/src/main/java/envoy/client/net/WriteProxy.java @@ -0,0 +1,102 @@ +package envoy.client.net; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import envoy.client.data.LocalDb; +import envoy.client.util.EnvoyLog; +import envoy.data.Message; +import envoy.event.MessageStatusChangeEvent; + +/** + * Implements methods to send {@link Message}s and + * {@link MessageStatusChangeEvent}s to the server or cache them inside a + * {@link LocalDb} depending on the online status.
+ *
+ * Project: envoy-client
+ * File: WriteProxy.java
+ * Created: 6 Feb 2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class WriteProxy { + + private final Client client; + private final LocalDb localDb; + + private static final Logger logger = EnvoyLog.getLogger(WriteProxy.class.getSimpleName()); + + /** + * Initializes a write proxy using a client and a local database. The + * corresponding cache processors are injected into the caches. + * + * @param client the client used to send messages and message status change + * events + * @param localDb the local database used to cache messages and message status + * change events + * @since Envoy v0.3-alpha + */ + public WriteProxy(Client client, LocalDb localDb) { + this.client = client; + this.localDb = localDb; + + // Initialize cache processors for messages and message status change events + localDb.getMessageCache().setProcessor(msg -> { + try { + client.sendMessage(msg); + } catch (IOException e) { + logger.log(Level.SEVERE, "Could not send cached message", e); + } + }); + localDb.getStatusCache().setProcessor(evt -> { + try { + client.sendEvent(evt); + } catch (IOException e) { + logger.log(Level.SEVERE, "Could not send cached message status change event", e); + } + }); + } + + /** + * Sends cached {@link Message}s and {@link MessageStatusChangeEvent}s to the + * server. + * + * @since Envoy v0.3-alpha + */ + public void flushCache() { + + // Send messages + localDb.getMessageCache().relay(); + + // Send message status change events + localDb.getStatusCache().relay(); + } + + /** + * Delivers a message to the server if online. Otherwise the message is cached + * inside the local database. + * + * @param message the message to send + * @throws IOException if the message could not be sent + * @since Envoy v0.3-alpha + */ + public void writeMessage(Message message) throws IOException { + if (client.isOnline()) client.sendMessage(message); + else localDb.getMessageCache().accept(message); + } + + /** + * Delivers a message status change event to the server if online. Otherwise the + * event is cached inside the local database. + * + * @param evt the event to send + * @throws IOException if the event could not be sent + * @since Envoy v0.3-alpha + */ + public void writeMessageStatusChangeEvent(MessageStatusChangeEvent evt) throws IOException { + if (client.isOnline()) client.sendEvent(evt); + else localDb.getStatusCache().accept(evt); + } +} From 3f7544cea3bae7e4ab86a5ba26a2498080600203 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 6 Feb 2020 21:28:02 +0100 Subject: [PATCH 219/474] Integrated WriteProxy into the sending process --- src/main/java/envoy/client/data/Chat.java | 12 +++-- src/main/java/envoy/client/ui/ChatWindow.java | 44 +++++++++---------- src/main/java/envoy/client/ui/Startup.java | 14 ++++-- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/main/java/envoy/client/data/Chat.java b/src/main/java/envoy/client/data/Chat.java index f10e816..49083a7 100644 --- a/src/main/java/envoy/client/data/Chat.java +++ b/src/main/java/envoy/client/data/Chat.java @@ -3,7 +3,7 @@ package envoy.client.data; import java.io.IOException; import java.io.Serializable; -import envoy.client.net.Client; +import envoy.client.net.WriteProxy; import envoy.client.ui.list.ComponentListModel; import envoy.data.Message; import envoy.data.Message.MessageStatus; @@ -52,22 +52,20 @@ public class Chat implements Serializable { * {@code READ} starting from the bottom and stopping once a read message is * found. * - * @param client the client instance used to notify the server about the message - * status changes + * @param writeProxy the write proxy instance used to notify the server about + * the message status changes * @throws IOException if a {@link MessageStatusChangeEvent} could not be * delivered to the server * @since Envoy v0.3-alpha */ - public void read(Client client) throws IOException { + public void read(WriteProxy writeProxy) throws IOException { for (int i = model.size() - 1; i >= 0; --i) { final Message m = model.get(i); if (m.getSenderId() == recipient.getId()) { if (m.getStatus() == MessageStatus.READ) break; else { m.setStatus(MessageStatus.READ); - - // TODO: Cache events in offline mode - client.sendEvent(new MessageStatusChangeEvent(m)); + writeProxy.writeMessageStatusChangeEvent(new MessageStatusChangeEvent(m)); } } } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 3abd54a..7d537bf 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -16,6 +16,7 @@ import envoy.client.data.LocalDb; import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.net.Client; +import envoy.client.net.WriteProxy; import envoy.client.ui.list.ComponentList; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; @@ -39,8 +40,9 @@ import envoy.event.MessageStatusChangeEvent; public class ChatWindow extends JFrame { // User specific objects - private Client client; - private LocalDb localDb; + private Client client; + private WriteProxy writeProxy; + private LocalDb localDb; // GUI components private JPanel contentPane = new JPanel(); @@ -211,7 +213,7 @@ public class ChatWindow extends JFrame { // Listen to received messages EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { - Message message = ((MessageCreationEvent) evt).get(); + Message message = ((MessageCreationEvent) evt).get(); Chat chat = localDb.getChats().stream().filter(c -> c.getRecipient().getId() == message.getSenderId()).findFirst().get(); chat.appendMessage(message); @@ -301,8 +303,7 @@ public class ChatWindow extends JFrame { .build(); // Send message - // TODO: Store offline messages - client.sendMessage(message); + writeProxy.writeMessage(message); // Add message to PersistentLocalDb and update UI currentChat.appendMessage(message); @@ -345,7 +346,7 @@ public class ChatWindow extends JFrame { private void readCurrentChat() { try { - currentChat.read(client); + currentChat.read(writeProxy); messageList.synchronizeModel(); } catch (IOException e) { e.printStackTrace(); @@ -354,24 +355,23 @@ public class ChatWindow extends JFrame { } /** - * Sets the {@link Client} used by this {@link ChatWindow}. + * Initializes the components responsible server communication and + * persistence.
+ *
+ * This will trigger the display of the contact list. * - * @param client the {@link Client} used to send and receive messages - * @since Envoy v0.2-alpha + * @param client the client used to send and receive messages + * @param localDb the local database used to manage stored messages + * and users + * @param writeProxy the write proxy used to send messages and status change + * events to the server or cache them inside the local + * database + * @since Envoy v0.3-alpha */ - public void setClient(Client client) { this.client = client; } - - /** - * Sets the {@link LocalDb} used by this {@link ChatWindow}. After - * invoking this - * method, users and chats will be loaded from the database into the GUI. - * - * @param localDb the {@link LocalDb} used to manage stored messages - * and users - * @since Envoy v0.2-alpha - */ - public void setLocalDB(LocalDb localDb) { - this.localDb = localDb; + public void initContent(Client client, LocalDb localDb, WriteProxy writeProxy) { + this.client = client; + this.localDb = localDb; + this.writeProxy = writeProxy; loadUsersAndChats(); } } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 1a38da9..1c68e41 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -15,6 +15,7 @@ import envoy.client.Config; import envoy.client.Settings; import envoy.client.data.*; import envoy.client.net.Client; +import envoy.client.net.WriteProxy; import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; import envoy.data.Message; @@ -148,14 +149,19 @@ public class Startup { JOptionPane.WARNING_MESSAGE); } - // Save all users to the local database - if (client.isOnline()) localDb.setUsers(client.getUsers()); + // Initialize write proxy + final WriteProxy writeProxy = client.createWriteProxy(localDb); + + // Save all users to the local database and flush cache + if (client.isOnline()) { + localDb.setUsers(client.getUsers()); + writeProxy.flushCache(); + } // Display ChatWindow and StatusTrayIcon EventQueue.invokeLater(() -> { try { - chatWindow.setClient(client); - chatWindow.setLocalDB(localDb); + chatWindow.initContent(client, localDb, writeProxy); try { new StatusTrayIcon(chatWindow).show(); From fe6cc9f4648d456f3f1cf120de01c329c2327faf Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 6 Feb 2020 21:42:17 +0100 Subject: [PATCH 220/474] Persisting cache in PersistentLocalDb --- src/main/java/envoy/client/data/Cache.java | 4 +++- src/main/java/envoy/client/data/LocalDb.java | 8 ++++---- .../envoy/client/data/PersistentLocalDb.java | 20 ++++++++++++++----- src/main/java/envoy/client/ui/Startup.java | 2 +- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/main/java/envoy/client/data/Cache.java b/src/main/java/envoy/client/data/Cache.java index 458cb0a..80ef26f 100644 --- a/src/main/java/envoy/client/data/Cache.java +++ b/src/main/java/envoy/client/data/Cache.java @@ -1,5 +1,6 @@ package envoy.client.data; +import java.io.Serializable; import java.util.LinkedList; import java.util.Queue; import java.util.function.Consumer; @@ -18,12 +19,13 @@ import envoy.client.util.EnvoyLog; * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ -public class Cache implements Consumer { +public class Cache implements Consumer, Serializable { private final Queue elements = new LinkedList<>(); private transient Consumer processor; private static final Logger logger = EnvoyLog.getLogger(Cache.class.getSimpleName()); + private static final long serialVersionUID = 7343544675545545076L; /** * Adds an element to the cache. diff --git a/src/main/java/envoy/client/data/LocalDb.java b/src/main/java/envoy/client/data/LocalDb.java index a606856..8034e2a 100644 --- a/src/main/java/envoy/client/data/LocalDb.java +++ b/src/main/java/envoy/client/data/LocalDb.java @@ -24,8 +24,8 @@ public abstract class LocalDb { protected Map users = new HashMap<>(); protected List chats = new ArrayList<>(); protected IdGenerator idGenerator; - protected Cache messageCache; - protected Cache statusCache; + protected Cache messageCache = new Cache<>(); + protected Cache statusCache = new Cache<>(); /** * Initializes a storage space for a user-specific list of chats. @@ -52,12 +52,12 @@ public abstract class LocalDb { public void loadUsers() throws Exception {} /** - * Loads all chat data of the client user. + * Loads all data of the client user. * * @throws Exception if the loading process failed * @since Envoy v0.3-alpha */ - public void loadChats() throws Exception {} + public void loadUserData() throws Exception {} /** * Loads the ID generator. Any exception thrown during this process is ignored. diff --git a/src/main/java/envoy/client/data/PersistentLocalDb.java b/src/main/java/envoy/client/data/PersistentLocalDb.java index 7052c60..d6e594a 100644 --- a/src/main/java/envoy/client/data/PersistentLocalDb.java +++ b/src/main/java/envoy/client/data/PersistentLocalDb.java @@ -23,7 +23,7 @@ import envoy.util.SerializationUtils; */ public class PersistentLocalDb extends LocalDb { - private File localDBDir, localDBFile, usersFile, idGeneratorFile; + private File localDBDir, localDBFile, usersFile, idGeneratorFile, messageCacheFile, statusCacheFile; /** * Initializes an empty local database without a directory. All changes made to @@ -63,7 +63,9 @@ public class PersistentLocalDb extends LocalDb { @Override public void initializeUserStorage() { if (user == null) throw new NullPointerException("Client user is null"); - localDBFile = new File(localDBDir, user.getId() + ".db"); + localDBFile = new File(localDBDir, user.getId() + ".db"); + messageCacheFile = new File(localDBDir, user.getId() + "_message_cache.db"); + statusCacheFile = new File(localDBDir, user.getId() + "_status_cache.db"); } @Override @@ -71,8 +73,12 @@ public class PersistentLocalDb extends LocalDb { // Save users SerializationUtils.write(usersFile, users); - // Save chats - if (user != null) SerializationUtils.write(localDBFile, chats); + // Save user data + if (user != null) { + SerializationUtils.write(localDBFile, chats); + SerializationUtils.write(messageCacheFile, messageCache); + SerializationUtils.write(statusCacheFile, statusCache); + } // Save id generator if (hasIdGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator); @@ -82,7 +88,11 @@ public class PersistentLocalDb extends LocalDb { public void loadUsers() throws ClassNotFoundException, IOException { users = SerializationUtils.read(usersFile, HashMap.class); } @Override - public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } + public void loadUserData() throws ClassNotFoundException, IOException { + chats = SerializationUtils.read(localDBFile, ArrayList.class); + messageCache = SerializationUtils.read(messageCacheFile, Cache.class); + statusCache = SerializationUtils.read(statusCacheFile, Cache.class); + } @Override public void loadIdGenerator() { diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 1c68e41..46f7951 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -138,7 +138,7 @@ public class Startup { // Initialize chats in local database try { localDb.initializeUserStorage(); - localDb.loadChats(); + localDb.loadUserData(); } catch (FileNotFoundException e) { // The local database file has not yet been created, probably first login } catch (Exception e) { From abd02b2c6f5bceac14c184178f7f01876d8cbec0 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 6 Feb 2020 22:17:14 +0100 Subject: [PATCH 221/474] Implemented login through command line arguments * Moved Config and ConfigItem to data package * Added mandatory property to ConfigItem * Added user and password ConfigItems to Config --- src/main/java/envoy/client/Settings.java | 1 + .../java/envoy/client/{ => data}/Config.java | 59 +++++++++++++++---- .../envoy/client/{ => data}/ConfigItem.java | 46 ++++++++++++--- .../envoy/client/data/PersistentLocalDb.java | 1 - src/main/java/envoy/client/net/Client.java | 2 +- src/main/java/envoy/client/ui/Startup.java | 7 +-- src/main/java/envoy/client/util/EnvoyLog.java | 2 +- 7 files changed, 91 insertions(+), 27 deletions(-) rename src/main/java/envoy/client/{ => data}/Config.java (69%) rename src/main/java/envoy/client/{ => data}/ConfigItem.java (56%) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index 02b6c88..efb03d6 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -6,6 +6,7 @@ import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; +import envoy.client.data.Config; import envoy.client.ui.Color; import envoy.client.ui.Theme; import envoy.util.SerializationUtils; diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/data/Config.java similarity index 69% rename from src/main/java/envoy/client/Config.java rename to src/main/java/envoy/client/data/Config.java index 24e7780..1f351ea 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/data/Config.java @@ -1,9 +1,12 @@ -package envoy.client; +package envoy.client.data; import java.io.File; +import java.security.NoSuchAlgorithmException; import java.util.*; +import java.util.function.Function; import java.util.logging.Level; +import envoy.data.LoginCredentials; import envoy.exception.EnvoyException; /** @@ -26,14 +29,15 @@ public class Config { private static Config config; private Config() { - items.put("server", new ConfigItem<>("server", "s", (input) -> input, null)); - items.put("port", new ConfigItem<>("port", "p", (input) -> Integer.parseInt(input), null)); - items.put("localDB", new ConfigItem<>("localDB", "db", (input) -> new File(input), new File("localDB"))); - items.put("ignoreLocalDB", new ConfigItem<>("ignoreLocalDB", "nodb", (input) -> Boolean.parseBoolean(input), false)); - items.put("homeDirectory", - new ConfigItem<>("homeDirectory", "h", (input) -> new File(input), new File(System.getProperty("user.home"), ".envoy"))); - items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", (input) -> Level.parse(input), Level.CONFIG)); - items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", (input) -> Level.parse(input), Level.FINEST)); + items.put("server", new ConfigItem<>("server", "s", Function.identity(), null, true)); + items.put("port", new ConfigItem<>("port", "p", Integer::parseInt, null, true)); + items.put("localDB", new ConfigItem<>("localDB", "db", File::new, new File("localDB"), true)); + items.put("ignoreLocalDB", new ConfigItem<>("ignoreLocalDB", "nodb", Boolean::parseBoolean, false, false)); + items.put("homeDirectory", new ConfigItem<>("homeDirectory", "h", File::new, new File(System.getProperty("user.home"), ".envoy"), true)); + items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", Level::parse, Level.CONFIG, true)); + items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", Level::parse, Level.FINEST, true)); + items.put("user", new ConfigItem<>("user", "u", Function.identity())); + items.put("password", new ConfigItem<>("password", "pw", String::toCharArray)); } /** @@ -95,10 +99,12 @@ public class Config { } /** - * @return {@code true} if server, port and localDB directory are known. + * @return {@code true} if all mandatory config items are initialized * @since Envoy v0.1-alpha */ - public boolean isInitialized() { return items.values().stream().map(ConfigItem::get).noneMatch(Objects::isNull); } + public boolean isInitialized() { + return items.values().stream().filter(ConfigItem::isMandatory).map(ConfigItem::get).noneMatch(Objects::isNull); + } /** * @return the host name of the Envoy server @@ -141,4 +147,35 @@ public class Config { * @since Envoy v0.2-alpha */ public Level getConsoleLevelBarrier() { return (Level) items.get("consoleLevelBarrier").get(); } + + /** + * @return the user name + * @since Envoy v0.3-alpha + */ + public String getUser() { return (String) items.get("user").get(); } + + /** + * @return the password + * @since Envoy v0.3-alpha + */ + public char[] getPassword() { return (char[]) items.get("password").get(); } + + /** + * @return {@code true} if user name and password are set + * @since Envoy v0.3-alpha + */ + public boolean hasLoginCredentials() { return getUser() != null && getPassword() != null; } + + /** + * @return login credentials for the specified user name and password, without + * the registration option + * @since Envoy v0.3-alpha + */ + public LoginCredentials getLoginCredentials() { + try { + return new LoginCredentials(getUser(), getPassword(), false); + } catch (NoSuchAlgorithmException e) { + return null; + } + } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ConfigItem.java b/src/main/java/envoy/client/data/ConfigItem.java similarity index 56% rename from src/main/java/envoy/client/ConfigItem.java rename to src/main/java/envoy/client/data/ConfigItem.java index 87e927b..440a81c 100644 --- a/src/main/java/envoy/client/ConfigItem.java +++ b/src/main/java/envoy/client/data/ConfigItem.java @@ -1,4 +1,4 @@ -package envoy.client; +package envoy.client.data; import java.util.function.Function; @@ -9,49 +9,70 @@ import java.util.function.Function; * Project: envoy-clientChess
* File: ConfigItem.javaEvent.java
* Created: 21.12.2019
- * + * * @author Kai S. K. Engelbart * @param the type of the config item's value * @since Envoy v0.2-alpha */ public class ConfigItem { - private String commandLong, commandShort; - private Function parseFunction; - private T value; + private final String commandLong, commandShort; + private final Function parseFunction; + private final boolean mandatory; + + private T value; /** * Initializes a {@link ConfigItem} - * + * * @param commandLong the long command line argument to set this value * @param commandShort the short command line argument to set this value * @param parseFunction the {@code Function} that parses the value * from a string * @param defaultValue the optional default value to set before parsing + * @param mandatory indicated that this config item must be initialized with + * a non-null value * @since Envoy v0.2-alpha */ - public ConfigItem(String commandLong, String commandShort, Function parseFunction, T defaultValue) { + public ConfigItem(String commandLong, String commandShort, Function parseFunction, T defaultValue, boolean mandatory) { this.commandLong = commandLong; this.commandShort = commandShort; this.parseFunction = parseFunction; + this.mandatory = mandatory; value = defaultValue; } + /** + * Initializes an optional {@link ConfigItem} without a default value. + * + * @param commandLong the long command line argument to set this value + * @param commandShort the short command line argument to set this value + * @param parseFunction the {@code Function} that parses the value + * from a string + * @since Envoy v0.3-alpha + */ + public ConfigItem(String commandLong, String commandShort, Function parseFunction) { + this(commandLong, commandShort, parseFunction, null, false); + } + /** * Parses this {@ConfigItem}'s value from a string + * * @param input the string to parse from * @since Envoy v0.2-alpha */ public void parse(String input) { value = parseFunction.apply(input); } /** - * @return The long command line argument to set the value of this {@link ConfigItem} + * @return The long command line argument to set the value of this + * {@link ConfigItem} * @since Envoy v0.2-alpha */ public String getCommandLong() { return commandLong; } /** - * @return The short command line argument to set the value of this {@link ConfigItem} + * @return The short command line argument to set the value of this + * {@link ConfigItem} * @since Envoy v0.2-alpha */ public String getCommandShort() { return commandShort; } @@ -61,4 +82,11 @@ public class ConfigItem { * @since Envoy v0.2-alpha */ public T get() { return value; } + + /** + * @return {@code true} if this {@link ConfigItem} is mandatory for successful + * application initialization + * @since Envoy v0.3-alpha + */ + public boolean isMandatory() { return mandatory; } } diff --git a/src/main/java/envoy/client/data/PersistentLocalDb.java b/src/main/java/envoy/client/data/PersistentLocalDb.java index d6e594a..0a04729 100644 --- a/src/main/java/envoy/client/data/PersistentLocalDb.java +++ b/src/main/java/envoy/client/data/PersistentLocalDb.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; -import envoy.client.ConfigItem; import envoy.data.IdGenerator; import envoy.util.SerializationUtils; diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 29b2f03..d742f1b 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -9,8 +9,8 @@ import java.util.logging.Logger; import javax.naming.TimeLimitExceededException; -import envoy.client.Config; import envoy.client.data.Cache; +import envoy.client.data.Config; import envoy.client.data.LocalDb; import envoy.client.util.EnvoyLog; import envoy.data.*; diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 46f7951..13f8676 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -11,7 +11,6 @@ import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; -import envoy.client.Config; import envoy.client.Settings; import envoy.client.data.*; import envoy.client.net.Client; @@ -63,7 +62,7 @@ public class Startup { // Override configuration values with command line arguments if (args.length > 0) config.load(args); - // Check if all configuration values have been initialized + // Check if all mandatory configuration values have been initialized if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined"); } catch (Exception e) { JOptionPane @@ -76,8 +75,8 @@ public class Startup { EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); - // Ask the user for their user name and password - LoginCredentials credentials = new LoginDialog().getCredentials(); + // Acquire login credentials + LoginCredentials credentials = config.hasLoginCredentials() ? config.getLoginCredentials() : new LoginDialog().getCredentials(); if (credentials == null) { logger.info("The login process has been aborted by the user. Exiting..."); diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index b59b714..ae6c6e5 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -4,7 +4,7 @@ import java.io.File; import java.io.IOException; import java.util.logging.*; -import envoy.client.Config; +import envoy.client.data.Config; /** * Project: envoy-client
From 5ed8c162bbb142743147a3f6b92b329f506d740e Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Thu, 6 Feb 2020 22:19:33 +0100 Subject: [PATCH 222/474] Implemented advanced UI --- src/main/java/envoy/client/ui/ChatWindow.java | 182 ++++++++++++++++-- .../envoy/client/ui/UserListRenderer.java | 3 + .../envoy/client/ui/list/ComponentList.java | 6 +- 3 files changed, 170 insertions(+), 21 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 3abd54a..631fe7c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -53,6 +53,19 @@ public class ChatWindow extends JFrame { private PrimaryButton postButton = new PrimaryButton("Post"); private PrimaryButton settingsButton = new PrimaryButton("Settings"); + // Contacts Header + private JPanel contactsHeader = new JPanel(); + private JTextPane contactsDisplay = new JTextPane(); + private PrimaryButton addContact = new PrimaryButton("+"); + + // Search Contacts + private JPanel searchPane = new JPanel(); + private PrimaryButton cancelButton = new PrimaryButton("x"); + private PrimaryTextArea searchField = new PrimaryTextArea(space); + private PrimaryScrollPane possibleContacts = new PrimaryScrollPane(); + private ComponentList contactList; // TODO Implement data rendering model as already done with the + // messages + private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class.getSimpleName()); // GUI component spacing @@ -78,9 +91,9 @@ public class ChatWindow extends JFrame { setContentPane(contentPane); GridBagLayout gbl_contentPane = new GridBagLayout(); gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; - gbl_contentPane.rowHeights = new int[] { 1, 1, 1 }; + gbl_contentPane.rowHeights = new int[] { 1, 1, 1, 1 }; gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; - gbl_contentPane.rowWeights = new double[] { 0.05, 1.0, 0.07 }; + gbl_contentPane.rowWeights = new double[] { 0.03, 0.001, 1.0, 0.005 }; contentPane.setLayout(gbl_contentPane); // TODO: messageList.setFocusTraversalKeysEnabled(false); @@ -95,11 +108,13 @@ public class ChatWindow extends JFrame { GridBagConstraints gbc_scrollPane = new GridBagConstraints(); gbc_scrollPane.fill = GridBagConstraints.BOTH; gbc_scrollPane.gridwidth = 2; + gbc_scrollPane.gridheight = 2; gbc_scrollPane.gridx = 1; gbc_scrollPane.gridy = 1; gbc_scrollPane.insets = insets; - contentPane.add(scrollPane, gbc_scrollPane); + + drawChatBox(gbc_scrollPane); // Message enter field messageEnterTextArea.addKeyListener(new KeyAdapter() { @@ -115,7 +130,7 @@ public class ChatWindow extends JFrame { GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; gbc_messageEnterTextfield.gridx = 1; - gbc_messageEnterTextfield.gridy = 2; + gbc_messageEnterTextfield.gridy = 3; gbc_messageEnterTextfield.insets = insets; @@ -126,7 +141,7 @@ public class ChatWindow extends JFrame { gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; gbc_moveSelectionPostButton.gridx = 2; - gbc_moveSelectionPostButton.gridy = 2; + gbc_moveSelectionPostButton.gridy = 3; gbc_moveSelectionPostButton.insets = insets; @@ -172,22 +187,27 @@ public class ChatWindow extends JFrame { final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); - // Select current chat - currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); + for (int i = 0; i < contentPane.getComponents().length; i++) { + if (contentPane.getComponent(i).equals(searchPane)) { drawChatBox(gbc_scrollPane); } + } + if (user != null) { + // Select current chat + currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); - // Read current chat - readCurrentChat(); + // Read current chat + readCurrentChat(); - // Set chat title - textPane.setText(currentChat.getRecipient().getName()); + // Set chat title + textPane.setText(currentChat.getRecipient().getName()); - // Update model and scroll down - messageList.setModel(currentChat.getModel()); - scrollPane.setChatOpened(true); + // Update model and scroll down + messageList.setModel(currentChat.getModel()); + scrollPane.setChatOpened(true); - messageList.synchronizeModel(); - revalidate(); - repaint(); + messageList.synchronizeModel(); + revalidate(); + repaint(); + } } }); @@ -197,15 +217,104 @@ public class ChatWindow extends JFrame { GridBagConstraints gbc_userList = new GridBagConstraints(); gbc_userList.fill = GridBagConstraints.VERTICAL; gbc_userList.gridx = 0; - gbc_userList.gridy = 1; + gbc_userList.gridy = 2; gbc_userList.anchor = GridBagConstraints.PAGE_START; gbc_userList.insets = insets; - applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); contentPane.add(userList, gbc_userList); contentPane.revalidate(); + // Contacts Search + GridBagConstraints gbc_searchPane = new GridBagConstraints(); + gbc_searchPane.fill = GridBagConstraints.BOTH; + gbc_searchPane.gridwidth = 2; + gbc_searchPane.gridheight = 2; + gbc_searchPane.gridx = 1; + gbc_searchPane.gridy = 1; + + gbc_searchPane.insets = insets; + + GridBagLayout gbl_contactsSearch = new GridBagLayout(); + gbl_contactsSearch.columnWidths = new int[] { 1, 1 }; + gbl_contactsSearch.rowHeights = new int[] { 1, 1 }; + gbl_contactsSearch.columnWeights = new double[] { 1, 0.1 }; + gbl_contactsSearch.rowWeights = new double[] { 0.001, 1 }; + searchPane.setLayout(gbl_contactsSearch); + + GridBagConstraints gbc_searchField = new GridBagConstraints(); + gbc_searchField.fill = GridBagConstraints.BOTH; + gbc_searchField.gridx = 0; + gbc_searchField.gridy = 0; + gbc_searchField.insets = new Insets(7, 4, 4, 4); + + searchPane.add(searchField, gbc_searchField); + + GridBagConstraints gbc_cancelButton = new GridBagConstraints(); + gbc_cancelButton.fill = GridBagConstraints.BOTH; + gbc_cancelButton.gridx = 1; + gbc_cancelButton.gridy = 0; + gbc_cancelButton.insets = new Insets(7, 4, 4, 4); + + cancelButton.addActionListener((evt) -> { drawChatBox(gbc_scrollPane); }); + + searchPane.add(cancelButton, gbc_cancelButton); + + possibleContacts.setViewportView(contactList); + + GridBagConstraints gbc_possibleContacts = new GridBagConstraints(); + gbc_possibleContacts.fill = GridBagConstraints.BOTH; + gbc_possibleContacts.gridwidth = 2; + gbc_possibleContacts.gridx = 0; + gbc_possibleContacts.gridy = 1; + + gbc_possibleContacts.insets = insets; + + searchPane.add(possibleContacts, gbc_possibleContacts); + + // Contacts Header + + GridBagConstraints gbc_contactsHeader = new GridBagConstraints(); + gbc_contactsHeader.fill = GridBagConstraints.BOTH; + gbc_contactsHeader.gridx = 0; + gbc_contactsHeader.gridy = 1; + gbc_contactsHeader.insets = insets; + + GridBagLayout gbl_contactHeader = new GridBagLayout(); + gbl_contactHeader.columnWidths = new int[] { 1, 1 }; + gbl_contactHeader.rowHeights = new int[] { 1 }; + gbl_contactHeader.columnWeights = new double[] { 1, 1 }; + gbl_contactHeader.rowWeights = new double[] { 1 }; + contactsHeader.setLayout(gbl_contactHeader); + + contactsDisplay.setEditable(false); + contactsDisplay.setFont(new Font("Arial", Font.PLAIN, 12)); + contactsDisplay.setText("Contacts"); + + GridBagConstraints gbc_contactsDisplay = new GridBagConstraints(); + gbc_contactsDisplay.fill = GridBagConstraints.BOTH; + gbc_contactsDisplay.gridx = 0; + gbc_contactsDisplay.gridy = 0; + + contactsHeader.add(contactsDisplay, gbc_contactsDisplay); + + addContact.setFont(new Font("Arial", Font.PLAIN, 15)); + + GridBagConstraints gbc_addContact = new GridBagConstraints(); + gbc_addContact.fill = GridBagConstraints.BOTH; + gbc_addContact.gridx = 1; + gbc_addContact.gridy = 0; + gbc_addContact.insets = insets; + + addContact.addActionListener((evt) -> { drawContactSearch(gbc_searchPane); }); + + contactsHeader.add(addContact, gbc_addContact); + + applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + + contentPane.add(contactsHeader, gbc_contactsHeader); + contentPane.revalidate(); + // Listen to theme changes EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get())); @@ -285,6 +394,22 @@ public class ChatWindow extends JFrame { userList.setSelectionBackground(theme.getSelectionColor()); userList.setForeground(theme.getUserNameColor()); userList.setBackground(theme.getCellColor()); + // contacts header + contactsHeader.setBackground(theme.getCellColor()); + contactsDisplay.setBackground(theme.getCellColor()); + contactsDisplay.setForeground(theme.getUserNameColor()); + addContact.setBackground(theme.getInteractableBackgroundColor()); + addContact.setForeground(theme.getInteractableForegroundColor()); + // SearchPane + searchPane.setBackground(theme.getCellColor()); + searchField.setBackground(theme.getBackgroundColor()); + searchField.setForeground(theme.getUserNameColor()); + cancelButton.setBackground(theme.getInteractableBackgroundColor()); + cancelButton.setForeground(theme.getInteractableForegroundColor()); + // TODO: Uncomment if renderer is implemented + // contactList.setForeground(theme.getMessageColorChat()); + // contactList.setBackground(theme.getCellColor()); + possibleContacts.applyTheme(theme); } private void postMessage() { @@ -352,6 +477,25 @@ public class ChatWindow extends JFrame { logger.log(Level.WARNING, "Couldn't notify server about message status change", e); } } + + + private void drawChatBox(GridBagConstraints gbc_scrollPane) { + contentPane.remove(searchPane); + contentPane.add(scrollPane, gbc_scrollPane); + contentPane.revalidate(); + contentPane.repaint(); + } + + private void drawContactSearch(GridBagConstraints gbc_searchPane) { + currentChat = null; + userList.removeSelectionInterval(0, userList.getModel().getSize() - 1); + messageList.setModel(null); + textPane.setText(""); + contentPane.remove(scrollPane); + contentPane.add(searchPane, gbc_searchPane); + contentPane.revalidate(); + contentPane.repaint(); + } /** * Sets the {@link Client} used by this {@link ChatWindow}. diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index 9441801..8c63ad7 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -1,6 +1,7 @@ package envoy.client.ui; import java.awt.Component; +import java.awt.Dimension; import javax.swing.JLabel; import javax.swing.JList; @@ -41,6 +42,8 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { final String name = value.getName(); final UserStatus status = value.getStatus(); + this.setPreferredSize(new Dimension(100, 35)); + // Getting the UserNameColor of the current theme String textColor = null; textColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor().toHex(); diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index f62dc7b..4528b98 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -62,8 +62,10 @@ public class ComponentList extends JPanel { // Synchronize with new model this.model = model; - this.model.setComponentList(this); - synchronizeModel(); + if (model != null) { + this.model.setComponentList(this); + synchronizeModel(); + } else removeAll(); } /** From 581f2d9cdf2a3a1bc85cefaa42ae190ab8bbede1 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Fri, 7 Feb 2020 09:39:15 +0100 Subject: [PATCH 223/474] Added logging statement to WriteProxy#flushCache() --- src/main/java/envoy/client/net/WriteProxy.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/net/WriteProxy.java b/src/main/java/envoy/client/net/WriteProxy.java index 454751f..98206ae 100644 --- a/src/main/java/envoy/client/net/WriteProxy.java +++ b/src/main/java/envoy/client/net/WriteProxy.java @@ -62,10 +62,11 @@ public class WriteProxy { /** * Sends cached {@link Message}s and {@link MessageStatusChangeEvent}s to the * server. - * + * * @since Envoy v0.3-alpha */ public void flushCache() { + logger.info("Sending cached messages and message status change events..."); // Send messages localDb.getMessageCache().relay(); From fc57e39c8fa5f76ef00ae7b1a2e30350a3d8c42f Mon Sep 17 00:00:00 2001 From: Haramus Samsamus Date: Fri, 7 Feb 2020 13:44:09 +0100 Subject: [PATCH 224/474] Fixed Javadoc errors --- src/main/java/envoy/client/data/ConfigItem.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/envoy/client/data/ConfigItem.java b/src/main/java/envoy/client/data/ConfigItem.java index 440a81c..6a987cb 100644 --- a/src/main/java/envoy/client/data/ConfigItem.java +++ b/src/main/java/envoy/client/data/ConfigItem.java @@ -23,7 +23,7 @@ public class ConfigItem { private T value; /** - * Initializes a {@link ConfigItem} + * Initializes a {@link ConfigItem}. * * @param commandLong the long command line argument to set this value * @param commandShort the short command line argument to set this value @@ -56,7 +56,7 @@ public class ConfigItem { } /** - * Parses this {@ConfigItem}'s value from a string + * Parses this {@ConfigItem}'s value from a string. * * @param input the string to parse from * @since Envoy v0.2-alpha From ead2eab5a018c8be4fe0640ec5d000ce604ef71a Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 7 Feb 2020 15:27:26 +0100 Subject: [PATCH 225/474] Added the UserStatusChangeProcessor and its implementation this commit serves as solution to the merge conflict between f/user_status_change_processor and develop --- src/main/java/envoy/client/net/Client.java | 21 ++++++++-- .../client/net/UserStatusChangeProcessor.java | 40 +++++++++++++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 4 ++ 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/main/java/envoy/client/net/UserStatusChangeProcessor.java diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index d742f1b..9c52992 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -14,9 +14,7 @@ import envoy.client.data.Config; import envoy.client.data.LocalDb; import envoy.client.util.EnvoyLog; import envoy.data.*; -import envoy.event.Event; -import envoy.event.IdGeneratorRequest; -import envoy.event.MessageStatusChangeEvent; +import envoy.event.*; import envoy.util.SerializationUtils; /** @@ -100,6 +98,8 @@ public class Client implements Closeable { receiver.removeAllProcessors(); // Register processors for message and status handling + + // Process incoming messages final ReceivedMessageProcessor receivedMessageProcessor = new ReceivedMessageProcessor(); receiver.registerProcessor(Message.class, receivedMessageProcessor); @@ -109,6 +109,9 @@ public class Client implements Closeable { // Process message status changes receiver.registerProcessor(MessageStatusChangeEvent.class, new MessageStatusChangeEventProcessor()); + // Process user status changes + receiver.registerProcessor(UserStatusChangeEvent.class, new UserStatusChangeProcessor(this)); + // Process message ID generation receiver.registerProcessor(IdGenerator.class, localDb::setIdGenerator); @@ -207,4 +210,16 @@ public class Client implements Closeable { * @since Envoy v0.2-alpha */ public boolean isOnline() { return online; } + + /** + * @return the contacts of this {@link Client} + * @since Envoy v0.3-alpha + */ + public Contacts getContacts() { return contacts; } + + /** + * @param contacts the contacts to set + * @since Envoy v0.3-alpha + */ + public void setContacts(Contacts contacts) { this.contacts = contacts; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/net/UserStatusChangeProcessor.java b/src/main/java/envoy/client/net/UserStatusChangeProcessor.java new file mode 100644 index 0000000..4f98358 --- /dev/null +++ b/src/main/java/envoy/client/net/UserStatusChangeProcessor.java @@ -0,0 +1,40 @@ +package envoy.client.net; + +import java.util.List; +import java.util.function.Consumer; +import java.util.logging.Logger; + +import envoy.client.util.EnvoyLog; +import envoy.data.User; +import envoy.event.EventBus; +import envoy.event.UserStatusChangeEvent; + +/** + * Project: envoy-client
+ * File: UserStatusChangeProcessor.java
+ * Created: 2 Feb 2020
+ * + * @author Leon Hofmeister + * @since Envoy v0.3-alpha + */ +public class UserStatusChangeProcessor implements Consumer { + + private static final Logger logger = EnvoyLog.getLogger(UserStatusChangeProcessor.class.getSimpleName()); + private Client client; + + /** + * @param client the {@link Client} who receives an + * {@link UserStatusChangeEvent} + * @since Envoy v0.3-alpha + */ + public UserStatusChangeProcessor(Client client) { this.client = client; } + + @Override + public void accept(UserStatusChangeEvent evt) { + logger.info("Received " + evt); + List contacts = client.getContacts().getContacts(); + contacts.stream().filter((user) -> user.getId() == evt.getId()).findFirst().get().setStatus(evt.get()); + EventBus.getInstance().dispatch(evt); + } + +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 7d537bf..8a7723e 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -26,6 +26,7 @@ import envoy.data.MessageBuilder; import envoy.data.User; import envoy.event.EventBus; import envoy.event.MessageStatusChangeEvent; +import envoy.event.UserStatusChangeEvent; /** * Project: envoy-client
@@ -211,6 +212,9 @@ public class ChatWindow extends JFrame { // Listen to theme changes EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get())); + // Listen to UserStatus changes + EventBus.getInstance().register(UserStatusChangeEvent.class, (evt) -> { userList.revalidate(); userList.repaint(); }); + // Listen to received messages EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { Message message = ((MessageCreationEvent) evt).get(); From 778e76faa7dc81f7fcb119ca1417ac4e8c515aa4 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 7 Feb 2020 15:41:17 +0100 Subject: [PATCH 226/474] added newline at the end of Client file --- src/main/java/envoy/client/net/Client.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 9c52992..6199b3b 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -222,4 +222,4 @@ public class Client implements Closeable { * @since Envoy v0.3-alpha */ public void setContacts(Contacts contacts) { this.contacts = contacts; } -} \ No newline at end of file +} From f9ce464aaadb27bfb74f247087bf86f3f333f7f0 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 7 Feb 2020 15:43:33 +0100 Subject: [PATCH 227/474] added newline at the end of UserStatusChangeProcessor file --- src/main/java/envoy/client/net/UserStatusChangeProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/net/UserStatusChangeProcessor.java b/src/main/java/envoy/client/net/UserStatusChangeProcessor.java index 4f98358..280c834 100644 --- a/src/main/java/envoy/client/net/UserStatusChangeProcessor.java +++ b/src/main/java/envoy/client/net/UserStatusChangeProcessor.java @@ -37,4 +37,4 @@ public class UserStatusChangeProcessor implements Consumer Date: Fri, 7 Feb 2020 15:57:41 +0100 Subject: [PATCH 228/474] Redesigned UserStatusChangeProcessor to please @CyB3RC0nN0R s wishes --- .../envoy/client/net/UserStatusChangeProcessor.java | 11 ++++------- src/main/java/envoy/client/ui/ChatWindow.java | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/envoy/client/net/UserStatusChangeProcessor.java b/src/main/java/envoy/client/net/UserStatusChangeProcessor.java index 280c834..744e6e8 100644 --- a/src/main/java/envoy/client/net/UserStatusChangeProcessor.java +++ b/src/main/java/envoy/client/net/UserStatusChangeProcessor.java @@ -1,11 +1,9 @@ package envoy.client.net; -import java.util.List; import java.util.function.Consumer; import java.util.logging.Logger; import envoy.client.util.EnvoyLog; -import envoy.data.User; import envoy.event.EventBus; import envoy.event.UserStatusChangeEvent; @@ -19,8 +17,9 @@ import envoy.event.UserStatusChangeEvent; */ public class UserStatusChangeProcessor implements Consumer { - private static final Logger logger = EnvoyLog.getLogger(UserStatusChangeProcessor.class.getSimpleName()); - private Client client; + private Client client; + + private static final Logger logger = EnvoyLog.getLogger(UserStatusChangeProcessor.class.getSimpleName()); /** * @param client the {@link Client} who receives an @@ -32,9 +31,7 @@ public class UserStatusChangeProcessor implements Consumer contacts = client.getContacts().getContacts(); - contacts.stream().filter((user) -> user.getId() == evt.getId()).findFirst().get().setStatus(evt.get()); + client.getContacts().getContacts().stream().filter((user) -> user.getId() == evt.getId()).findFirst().get().setStatus(evt.get()); EventBus.getInstance().dispatch(evt); } - } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 8a7723e..0e12611 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -212,7 +212,7 @@ public class ChatWindow extends JFrame { // Listen to theme changes EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get())); - // Listen to UserStatus changes + // Listen to user status changes EventBus.getInstance().register(UserStatusChangeEvent.class, (evt) -> { userList.revalidate(); userList.repaint(); }); // Listen to received messages From 1fc85fe4fa332ac19548252779e06bdaf6f8d257 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 8 Feb 2020 11:43:02 +0100 Subject: [PATCH 229/474] Fixed threading issue when receiving unread messages --- src/main/java/envoy/client/net/Client.java | 22 +++++++++------------- src/main/java/envoy/client/ui/Startup.java | 10 +++++----- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 6199b3b..0d6a9d3 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -51,16 +51,17 @@ public class Client implements Closeable { * will block for up to 5 seconds. If the handshake does exceed this time limit, * an exception is thrown. * - * @param credentials the login credentials of the user - * @param localDb the local database used to persist the current - * {@link IdGenerator} - * @return a message cache containing all unread messages from the server that - * can be relayed after initialization + * @param credentials the login credentials of the user + * @param localDb the local database used to persist the current + * {@link IdGenerator} + * @param receivedMessageCache a message cache containing all unread messages + * from the server that can be relayed after + * initialization * @throws Exception if the online mode could not be entered or the request * failed for some other reason * @since Envoy v0.2-alpha */ - public Cache onlineInit(LoginCredentials credentials, LocalDb localDb) throws Exception { + public void onlineInit(LoginCredentials credentials, LocalDb localDb, Cache receivedMessageCache) throws Exception { // Establish TCP connection logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); socket = new Socket(config.getServer(), config.getPort()); @@ -69,13 +70,10 @@ public class Client implements Closeable { // Create message receiver receiver = new Receiver(socket.getInputStream()); - // Create cache for unread messages - final Cache cache = new Cache<>(); - // Register user creation processor, contact list processor and message cache receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); receiver.registerProcessor(Contacts.class, contacts -> { logger.info("Acquired contacts object " + contacts); this.contacts = contacts; }); - receiver.registerProcessor(Message.class, cache); + receiver.registerProcessor(Message.class, receivedMessageCache); // Start receiver new Thread(receiver).start(); @@ -104,7 +102,7 @@ public class Client implements Closeable { receiver.registerProcessor(Message.class, receivedMessageProcessor); // Relay cached unread messages - cache.setProcessor(receivedMessageProcessor); + receivedMessageCache.setProcessor(receivedMessageProcessor); // Process message status changes receiver.registerProcessor(MessageStatusChangeEvent.class, new MessageStatusChangeEventProcessor()); @@ -117,8 +115,6 @@ public class Client implements Closeable { // Request a generator if none is present or the existing one is consumed if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator(); - - return cache; } /** diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 13f8676..a976824 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -106,11 +106,11 @@ public class Startup { // Acquire the client user (with ID) either from the server or from the local // database, which triggers offline mode Client client = new Client(); - Cache cache = null; + Cache cache = new Cache<>(); try { // Try entering online mode first localDb.loadIdGenerator(); - cache = client.onlineInit(credentials, localDb); + client.onlineInit(credentials, localDb, cache); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); e1.printStackTrace(); @@ -162,6 +162,9 @@ public class Startup { try { chatWindow.initContent(client, localDb, writeProxy); + // Relay unread messages from cache + if (cache != null) cache.relay(); + try { new StatusTrayIcon(chatWindow).show(); @@ -180,9 +183,6 @@ public class Startup { } }); - // Relay unread messages from cache - if (cache != null) cache.relay(); - // Save Settings and PersistentLocalDb on shutdown Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { From 79da5e6979554257de77044111ec6ba4d7435c34 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sat, 8 Feb 2020 11:43:37 +0100 Subject: [PATCH 230/474] Implemented ContactRenderer and built a properScrollPane with list, etc. --- src/main/java/envoy/client/ui/ChatWindow.java | 58 +++++++------ .../client/ui/ContactsSearchRenderer.java | 83 +++++++++++++++++++ .../envoy/client/ui/MessageListRenderer.java | 2 +- 3 files changed, 117 insertions(+), 26 deletions(-) create mode 100644 src/main/java/envoy/client/ui/ContactsSearchRenderer.java diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 631fe7c..2366556 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -17,6 +17,7 @@ import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.net.Client; import envoy.client.ui.list.ComponentList; +import envoy.client.ui.list.ComponentListModel; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; import envoy.data.Message; @@ -54,17 +55,18 @@ public class ChatWindow extends JFrame { private PrimaryButton settingsButton = new PrimaryButton("Settings"); // Contacts Header - private JPanel contactsHeader = new JPanel(); - private JTextPane contactsDisplay = new JTextPane(); + private JPanel contactsHeader = new JPanel(); + private JTextPane contactsDisplay = new JTextPane(); private PrimaryButton addContact = new PrimaryButton("+"); // Search Contacts - private JPanel searchPane = new JPanel(); - private PrimaryButton cancelButton = new PrimaryButton("x"); - private PrimaryTextArea searchField = new PrimaryTextArea(space); - private PrimaryScrollPane possibleContacts = new PrimaryScrollPane(); - private ComponentList contactList; // TODO Implement data rendering model as already done with the - // messages + private final JPanel searchPane = new JPanel(); + private final PrimaryButton cancelButton = new PrimaryButton("x"); + private final PrimaryTextArea searchField = new PrimaryTextArea(space); + private final PrimaryScrollPane possibleContacts = new PrimaryScrollPane(); + private final ContactsSearchRenderer contactRenderer = new ContactsSearchRenderer(); + private final ComponentListModel contactsSearchModel = new ComponentListModel<>(); + private final ComponentList contactList = new ComponentList<>(contactRenderer); private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class.getSimpleName()); @@ -215,12 +217,12 @@ public class ChatWindow extends JFrame { userList.setBorder(new EmptyBorder(space, space, space, space)); GridBagConstraints gbc_userList = new GridBagConstraints(); - gbc_userList.fill = GridBagConstraints.VERTICAL; - gbc_userList.gridx = 0; - gbc_userList.gridy = 2; - gbc_userList.anchor = GridBagConstraints.PAGE_START; - gbc_userList.insets = insets; - + gbc_userList.fill = GridBagConstraints.VERTICAL; + gbc_userList.gridx = 0; + gbc_userList.gridy = 2; + gbc_userList.gridheight = 2; + gbc_userList.anchor = GridBagConstraints.PAGE_START; + gbc_userList.insets = insets; contentPane.add(userList, gbc_userList); contentPane.revalidate(); @@ -247,9 +249,9 @@ public class ChatWindow extends JFrame { gbc_searchField.gridx = 0; gbc_searchField.gridy = 0; gbc_searchField.insets = new Insets(7, 4, 4, 4); - + searchPane.add(searchField, gbc_searchField); - + GridBagConstraints gbc_cancelButton = new GridBagConstraints(); gbc_cancelButton.fill = GridBagConstraints.BOTH; gbc_cancelButton.gridx = 1; @@ -260,6 +262,8 @@ public class ChatWindow extends JFrame { searchPane.add(cancelButton, gbc_cancelButton); + contactList.setModel(contactsSearchModel); + possibleContacts.setBorder(new EmptyBorder(space, space, space, space)); possibleContacts.setViewportView(contactList); GridBagConstraints gbc_possibleContacts = new GridBagConstraints(); @@ -269,9 +273,10 @@ public class ChatWindow extends JFrame { gbc_possibleContacts.gridy = 1; gbc_possibleContacts.insets = insets; - + searchPane.add(possibleContacts, gbc_possibleContacts); + // Contacts Header GridBagConstraints gbc_contactsHeader = new GridBagConstraints(); @@ -305,7 +310,7 @@ public class ChatWindow extends JFrame { gbc_addContact.gridx = 1; gbc_addContact.gridy = 0; gbc_addContact.insets = insets; - + addContact.addActionListener((evt) -> { drawContactSearch(gbc_searchPane); }); contactsHeader.add(addContact, gbc_addContact); @@ -320,7 +325,7 @@ public class ChatWindow extends JFrame { // Listen to received messages EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { - Message message = ((MessageCreationEvent) evt).get(); + Message message = ((MessageCreationEvent) evt).get(); Chat chat = localDb.getChats().stream().filter(c -> c.getRecipient().getId() == message.getSenderId()).findFirst().get(); chat.appendMessage(message); @@ -355,6 +360,7 @@ public class ChatWindow extends JFrame { }); revalidate(); + repaint(); } /** @@ -406,9 +412,8 @@ public class ChatWindow extends JFrame { searchField.setForeground(theme.getUserNameColor()); cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor()); - // TODO: Uncomment if renderer is implemented - // contactList.setForeground(theme.getMessageColorChat()); - // contactList.setBackground(theme.getCellColor()); + contactList.setForeground(theme.getMessageColorChat()); + contactList.setBackground(theme.getCellColor()); possibleContacts.applyTheme(theme); } @@ -465,6 +470,9 @@ public class ChatWindow extends JFrame { localDb.getChats().add(new Chat(user)); }); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); + + revalidate(); + repaint(); }).start(); } @@ -477,15 +485,14 @@ public class ChatWindow extends JFrame { logger.log(Level.WARNING, "Couldn't notify server about message status change", e); } } - - + private void drawChatBox(GridBagConstraints gbc_scrollPane) { contentPane.remove(searchPane); contentPane.add(scrollPane, gbc_scrollPane); contentPane.revalidate(); contentPane.repaint(); } - + private void drawContactSearch(GridBagConstraints gbc_searchPane) { currentChat = null; userList.removeSelectionInterval(0, userList.getModel().getSize() - 1); @@ -494,6 +501,7 @@ public class ChatWindow extends JFrame { contentPane.remove(scrollPane); contentPane.add(searchPane, gbc_searchPane); contentPane.revalidate(); + contactRenderer.setScrollPane(possibleContacts); contentPane.repaint(); } diff --git a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java new file mode 100644 index 0000000..8f4e0e0 --- /dev/null +++ b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java @@ -0,0 +1,83 @@ +package envoy.client.ui; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; + +import javax.swing.*; + +import envoy.client.Settings; +import envoy.client.ui.list.ComponentList; +import envoy.client.ui.list.ComponentListCellRenderer; +import envoy.data.User; + +/** + * Defines how a contact is displayed.
+ *
+ * Project: envoy-client
+ * File: ContactsSearchRenderer.java
+ * Created: 08.02.2020
+ * + * @author Maximilian Käfer + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class ContactsSearchRenderer implements ComponentListCellRenderer { + + private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); + + + @Override + public JComponent getListCellComponent(ComponentList list, User value, boolean isSelected) { + final JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + if (isSelected) { + panel.setBackground(Color.DARK_GRAY); + panel.setForeground(Color.RED); + // TODO: Selection + // setBackground(list.getSelectionBackground()); + // setForeground(list.getSelectionForeground()); + } else { + panel.setBackground(list.getBackground()); + panel.setForeground(list.getForeground()); + } + + // TODO: Handle message attachments + + final String text = value.getName(); + + // Getting the UserColor in the Chat of the current theme + String textColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat().toHex(); + + JLabel display = new JLabel(String.format("

%s", textColor, text)); + display.setAlignmentX(Component.LEFT_ALIGNMENT); + display.setAlignmentY(Component.CENTER_ALIGNMENT); + display.setFont(new Font("Arial", Font.PLAIN, 16)); + panel.add(display); + + PrimaryButton add = new PrimaryButton("+"); + add.setFont(new Font("Arial", Font.PLAIN, 19)); + add.setPreferredSize(new Dimension(45, 45)); + add.setMinimumSize(new Dimension(45, 45)); + add.setMaximumSize(new Dimension(45, 45)); + + add.setBackground(list.getBackground()); + add.setForeground(list.getForeground()); + + panel.add(add); + + // Define some space to the messages below + panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0), BorderFactory.createEtchedBorder())); + + // Define a maximum height of 50px + Dimension size = new Dimension(435, 50); + panel.setMaximumSize(size); + panel.setMinimumSize(size); + panel.setPreferredSize(size); + + return panel; + } + + // TODO: Use this method properly + public void setScrollPane(PrimaryScrollPane scrollPane) { this.scrollPane = scrollPane; } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index c038e39..65ee63a 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -14,7 +14,7 @@ import envoy.data.Message; * Defines how a message is displayed.
*
* Project: envoy-client
- * File: UserListRenderer.java
+ * File: MessageListRenderer.java
* Created: 19 Oct 2019
* * @author Kai S. K. Engelbart From 7a2544bab6940327020dfbd93836211b4fbbad2e Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sun, 9 Feb 2020 16:26:36 +0100 Subject: [PATCH 231/474] Adding contacts technical aspects * Contact SearchResult from server is now getting processed and correctly displayed. * Sending a AddContact event to server, if button is pressed. * Added several interface objects --- pom.xml | 2 +- .../envoy/client/event/AddContactEvent.java | 42 +++++++++ .../envoy/client/event/SearchResultEvent.java | 32 +++++++ src/main/java/envoy/client/net/Client.java | 8 +- src/main/java/envoy/client/ui/ChatWindow.java | 87 +++++++++++++++++-- .../client/ui/ContactsSearchRenderer.java | 12 ++- 6 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 src/main/java/envoy/client/event/AddContactEvent.java create mode 100644 src/main/java/envoy/client/event/SearchResultEvent.java diff --git a/pom.xml b/pom.xml index 0b5487d..c7abb5f 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - develop-SNAPSHOT + f~contacts-SNAPSHOT diff --git a/src/main/java/envoy/client/event/AddContactEvent.java b/src/main/java/envoy/client/event/AddContactEvent.java new file mode 100644 index 0000000..8f356fa --- /dev/null +++ b/src/main/java/envoy/client/event/AddContactEvent.java @@ -0,0 +1,42 @@ +package envoy.client.event; + +import envoy.data.User; +import envoy.event.ContactOperation.Operation; +import envoy.event.Event; + +/** + * Project: envoy-client
+ * File: AddContactEvent.java
+ * Created: 09.02.2020
+ * + * @author Maximilian Käfer + * @since Envoy v0.3-alpha + */ +public class AddContactEvent implements Event { + + private User contact; + private Operation operation; + + private static final long serialVersionUID = 7855669140917046709L; + + /** + * Initializes a {@link AddContactEvent} + * + * @param contact the user to be added to the contacts + * @param operation the operation, which should be executed + * @since Envoy v0.3-alpha + */ + public AddContactEvent(User contact, Operation operation) { + this.contact = contact; + this.operation = operation; + } + + @Override + public User get() { return contact; } + + /** + * @return the operation, which should be executed + */ + public Operation getOperation() { return operation; } + +} diff --git a/src/main/java/envoy/client/event/SearchResultEvent.java b/src/main/java/envoy/client/event/SearchResultEvent.java new file mode 100644 index 0000000..dc834d3 --- /dev/null +++ b/src/main/java/envoy/client/event/SearchResultEvent.java @@ -0,0 +1,32 @@ +package envoy.client.event; + +import java.util.List; + +import envoy.data.User; +import envoy.event.Event; + +/** + * Project: envoy-client
+ * File: SearchResultEvent.java
+ * Created: 08.02.2020
+ * + * @author Maximilian Käfer + * @since Envoy v0.3-alpha + */ +public class SearchResultEvent implements Event> { + + private final List resultList; + + private static final long serialVersionUID = 2540321329192201277L; + + /** + * Initializes a {@link SearchResultEvent} + * + * @param resultList the List containing the contacts sent from the server + * @since Envoy v0.3-alpha + */ + public SearchResultEvent(List resultList) { this.resultList = resultList; } + + @Override + public List get() { return resultList; } +} diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 91e9040..c99ef13 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -11,11 +11,10 @@ import javax.naming.TimeLimitExceededException; import envoy.client.Config; import envoy.client.data.LocalDb; +import envoy.client.event.SearchResultEvent; import envoy.client.util.EnvoyLog; import envoy.data.*; -import envoy.event.Event; -import envoy.event.IdGeneratorRequest; -import envoy.event.MessageStatusChangeEvent; +import envoy.event.*; import envoy.util.SerializationUtils; /** @@ -111,6 +110,9 @@ public class Client implements Closeable { // Process message ID generation receiver.registerProcessor(IdGenerator.class, localDb::setIdGenerator); + // Process contact searches + receiver.registerProcessor(Contacts.class, contacts -> EventBus.getInstance().dispatch(new SearchResultEvent(contacts.getContacts()))); + // Request a generator if none is present or the existing one is consumed if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator(); diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 2366556..206f670 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -9,12 +9,13 @@ import java.util.logging.Logger; import javax.swing.*; import javax.swing.border.EmptyBorder; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import envoy.client.Settings; import envoy.client.data.Chat; import envoy.client.data.LocalDb; -import envoy.client.event.MessageCreationEvent; -import envoy.client.event.ThemeChangeEvent; +import envoy.client.event.*; import envoy.client.net.Client; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListModel; @@ -24,8 +25,8 @@ import envoy.data.Message; import envoy.data.Message.MessageStatus; import envoy.data.MessageBuilder; import envoy.data.User; -import envoy.event.EventBus; -import envoy.event.MessageStatusChangeEvent; +import envoy.event.*; +import envoy.event.ContactOperation.Operation; /** * Project: envoy-client
@@ -47,6 +48,7 @@ public class ChatWindow extends JFrame { private JPanel contentPane = new JPanel(); private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); private JList userList = new JList<>(); + private DefaultListModel userListModel = new DefaultListModel<>(); private Chat currentChat; private ComponentList messageList = new ComponentList<>(new MessageListRenderer()); private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); @@ -65,7 +67,7 @@ public class ChatWindow extends JFrame { private final PrimaryTextArea searchField = new PrimaryTextArea(space); private final PrimaryScrollPane possibleContacts = new PrimaryScrollPane(); private final ContactsSearchRenderer contactRenderer = new ContactsSearchRenderer(); - private final ComponentListModel contactsSearchModel = new ComponentListModel<>(); + private final ComponentListModel contactsModel = new ComponentListModel<>(); private final ComponentList contactList = new ComponentList<>(contactRenderer); private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class.getSimpleName()); @@ -252,6 +254,43 @@ public class ChatWindow extends JFrame { searchPane.add(searchField, gbc_searchField); + // Sends event to server, if input has changed + searchField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent e) { + if (client.isOnline()) { + try { + if(!searchField.getText().isEmpty()) { + client.sendEvent(new ContactsRequest(searchField.getText())); + } else { + contactsModel.clear(); + revalidate(); + repaint(); + } + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + + @Override + public void insertUpdate(DocumentEvent e) { + if (client.isOnline()) { + try { + if(!searchField.getText().isEmpty()) { + client.sendEvent(new ContactsRequest(searchField.getText())); + } + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + + @Override + public void changedUpdate(DocumentEvent e) {} + }); + GridBagConstraints gbc_cancelButton = new GridBagConstraints(); gbc_cancelButton.fill = GridBagConstraints.BOTH; gbc_cancelButton.gridx = 1; @@ -262,7 +301,7 @@ public class ChatWindow extends JFrame { searchPane.add(cancelButton, gbc_cancelButton); - contactList.setModel(contactsSearchModel); + contactList.setModel(contactsModel); possibleContacts.setBorder(new EmptyBorder(space, space, space, space)); possibleContacts.setViewportView(contactList); @@ -276,7 +315,6 @@ public class ChatWindow extends JFrame { searchPane.add(possibleContacts, gbc_possibleContacts); - // Contacts Header GridBagConstraints gbc_contactsHeader = new GridBagConstraints(); @@ -359,6 +397,36 @@ public class ChatWindow extends JFrame { repaint(); }); + EventBus.getInstance().register(SearchResultEvent.class, (evt) -> { + contactsModel.clear(); + final java.util.List contacts = ((SearchResultEvent) evt).get(); + logger.info("Received contact search result " + contacts); + contacts.forEach(contactsModel::add); + revalidate(); + repaint(); + }); + + EventBus.getInstance().register(AddContactEvent.class, (evt) -> { + User contact = ((AddContactEvent) evt).get(); + Operation operation = ((AddContactEvent) evt).getOperation(); + try { + client.sendEvent(new ContactOperation(contact, operation)); + } catch (IOException e) { + e.printStackTrace(); + } + + // TODO: Not finished LocalDB update of contact list + // Add this user to the chats + // userListModel.addElement(contact); + // Check if user exists in local DB + // if (localDb.getChats().stream().filter(c -> c.getRecipient().getId() == + // contact.getId()).count() == 0) + // localDb.getChats().add(new Chat(contact)); + + revalidate(); + repaint(); + }); + revalidate(); repaint(); } @@ -461,7 +529,6 @@ public class ChatWindow extends JFrame { */ private void loadUsersAndChats() { new Thread(() -> { - DefaultListModel userListModel = new DefaultListModel<>(); localDb.getUsers().values().forEach(user -> { userListModel.addElement(user); @@ -511,7 +578,9 @@ public class ChatWindow extends JFrame { * @param client the {@link Client} used to send and receive messages * @since Envoy v0.2-alpha */ - public void setClient(Client client) { this.client = client; } + public void setClient(Client client) { + this.client = client; + } /** * Sets the {@link LocalDb} used by this {@link ChatWindow}. After diff --git a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java index 8f4e0e0..b435def 100644 --- a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java @@ -7,9 +7,12 @@ import java.awt.Font; import javax.swing.*; import envoy.client.Settings; +import envoy.client.event.AddContactEvent; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; import envoy.data.User; +import envoy.event.ContactOperation.Operation; +import envoy.event.EventBus; /** * Defines how a contact is displayed.
@@ -26,7 +29,6 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); - @Override public JComponent getListCellComponent(ComponentList list, User value, boolean isSelected) { final JPanel panel = new JPanel(); @@ -34,9 +36,7 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { if (isSelected) { panel.setBackground(Color.DARK_GRAY); panel.setForeground(Color.RED); - // TODO: Selection - // setBackground(list.getSelectionBackground()); - // setForeground(list.getSelectionForeground()); + } else { panel.setBackground(list.getBackground()); panel.setForeground(list.getForeground()); @@ -64,6 +64,10 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { add.setBackground(list.getBackground()); add.setForeground(list.getForeground()); + add.addActionListener((evt) -> { + EventBus.getInstance().dispatch(new AddContactEvent(value, Operation.ADD)); + }); + panel.add(add); // Define some space to the messages below From 6582e88a0206619d38b94283a452dd46cf833a9d Mon Sep 17 00:00:00 2001 From: delvh Date: Sun, 9 Feb 2020 20:43:12 +0100 Subject: [PATCH 232/474] Added handling of incorrect logins --- .../event/HandshakeSuccessfulEvent.java | 18 ++++ src/main/java/envoy/client/net/Client.java | 1 + .../java/envoy/client/ui/LoginDialog.java | 97 +++++++++++-------- src/main/java/envoy/client/ui/Startup.java | 2 +- 4 files changed, 79 insertions(+), 39 deletions(-) create mode 100644 src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java diff --git a/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java b/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java new file mode 100644 index 0000000..3322ce4 --- /dev/null +++ b/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java @@ -0,0 +1,18 @@ +package envoy.client.event; + +import envoy.event.Event; + +/** + * This {@link Event} indicates that a handshake completed successful + * + * Project: envoy-client
+ * File: HandshakeSuccessfulEvent.java
+ * Created: 8 Feb 2020
+ * + * @author Leon Hofmeister + * @since Envoy v0.3-alpha + */ +public class HandshakeSuccessfulEvent implements Event { + + private static final long serialVersionUID = -157972384126278855L; +} diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 0d6a9d3..f1432f6 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -74,6 +74,7 @@ public class Client implements Closeable { receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); receiver.registerProcessor(Contacts.class, contacts -> { logger.info("Acquired contacts object " + contacts); this.contacts = contacts; }); receiver.registerProcessor(Message.class, receivedMessageCache); + receiver.registerProcessor(HandshakeRejectionEvent.class, EventBus.getInstance()::dispatch); // Start receiver new Thread(receiver).start(); diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index d81ecc1..e58b0b1 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -2,20 +2,22 @@ package envoy.client.ui; import java.awt.*; import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import javax.swing.*; import javax.swing.border.EmptyBorder; +import envoy.client.event.HandshakeSuccessfulEvent; import envoy.data.LoginCredentials; +import envoy.event.EventBus; +import envoy.event.HandshakeRejectionEvent; /** * Project: envoy-client
* File: LoginDialog.java
* Created: 01.01.2020
- * + * * @author Kai S. K. Engelbart * @author Maximilian Käfer * @since Envoy v0.3-alpha @@ -28,8 +30,11 @@ public class LoginDialog extends JDialog { private JTextField textField; private JPasswordField passwordField; - private JPasswordField repeatPasswordField; - private JLabel lblRepeatPassword; + private JPasswordField repeatPasswordField; + private JLabel lblRepeatPassword; + private JLabel errorMessage; + + private GridBagConstraints gbc_errorMessage; private GridBagConstraints gbc_lblRepeatPassword; private GridBagConstraints gbc_repeatPasswordField; @@ -37,7 +42,7 @@ public class LoginDialog extends JDialog { /** * Displays a dialog enabling the user to enter their user name and password. - * + * * @since Envoy v0.3-alpha */ public LoginDialog() { @@ -97,12 +102,27 @@ public class LoginDialog extends JDialog { gbc_lblRepeatPassword.gridy = 2; } { - repeatPasswordField = new JPasswordField(); + repeatPasswordField = new JPasswordField(); gbc_repeatPasswordField = new GridBagConstraints(); gbc_repeatPasswordField.fill = GridBagConstraints.HORIZONTAL; gbc_repeatPasswordField.gridx = 1; gbc_repeatPasswordField.gridy = 2; } + { + EventBus.getInstance().register(HandshakeRejectionEvent.class, evt -> { + contentPanel.remove(errorMessage); + clearPasswordFields(); + // TODO delete - only for testing purposes + System.out.println("Caught HandshakeRejectionEvent with reason" + ((HandshakeRejectionEvent) evt).get()); + errorMessage = new JLabel(((HandshakeRejectionEvent) evt).get()); + gbc_errorMessage = new GridBagConstraints(); + gbc_errorMessage.gridx = 2; + gbc_errorMessage.gridy = 0; + gbc_errorMessage.fill = GridBagConstraints.HORIZONTAL; + gbc_errorMessage.insets = new Insets(5, 5, 5, 5); + contentPanel.add(errorMessage, gbc_errorMessage); + }); + } { JPanel buttonPane = new JPanel(); @@ -114,30 +134,24 @@ public class LoginDialog extends JDialog { JCheckBox registerCheckBox = new JCheckBox(); registerCheckBox.setAlignmentX(LEFT_ALIGNMENT); - registerCheckBox.addItemListener(new ItemListener() { + registerCheckBox.addItemListener(e -> { + switch (e.getStateChange()) { + case ItemEvent.SELECTED: + contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword); + contentPanel.add(repeatPasswordField, gbc_repeatPasswordField); + setSize(338, 160); + break; - @Override - public void itemStateChanged(ItemEvent e) { - switch (e.getStateChange()) { - case ItemEvent.SELECTED: - contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword); - contentPanel.add(repeatPasswordField, gbc_repeatPasswordField); - setSize(338, 160); - contentPanel.revalidate(); - contentPanel.repaint(); - break; - - case ItemEvent.DESELECTED: - if (repeatPasswordField.getParent() == contentPanel) { - contentPanel.remove(lblRepeatPassword); - contentPanel.remove(repeatPasswordField); - setSize(338, 123); - contentPanel.revalidate(); - contentPanel.repaint(); - } - break; - } + case ItemEvent.DESELECTED: + if (repeatPasswordField.getParent() == contentPanel) { + contentPanel.remove(lblRepeatPassword); + contentPanel.remove(repeatPasswordField); + setSize(338, 123); + } + break; } + contentPanel.revalidate(); + contentPanel.repaint(); }); buttonPane.add(registerCheckBox); @@ -148,18 +162,14 @@ public class LoginDialog extends JDialog { okButton.addActionListener((evt) -> { try { if (registerCheckBox.isSelected()) { - if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) { + // password checking + if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), true); - dispose(); - } else { - JOptionPane.showMessageDialog(this, "The repeated password is unequal to the origional password!"); - passwordField.setText(null); - repeatPasswordField.setText(null); + else { + JOptionPane.showMessageDialog(this, "The repeated password is not the origional password!"); + clearPasswordFields(); } - } else { - credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); - dispose(); - } + } else credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } @@ -178,6 +188,17 @@ public class LoginDialog extends JDialog { setModal(true); setVisible(true); + EventBus.getInstance().register(HandshakeSuccessfulEvent.class, evt -> this.dispose()); + } + + /** + * Resets the text stored by this + * + * @since Envoy v0.3-alpha + */ + public void clearPasswordFields() { + passwordField.setText(null); + repeatPasswordField.setText(null); } /** diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index a976824..7cd09a7 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -117,7 +117,7 @@ public class Startup { try { // Try entering offline mode localDb.loadUsers(); - User clientUser = localDb.getUsers().get(credentials.getName()); + User clientUser = localDb.getUsers().get(credentials.getIdentifier()); if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); client.setSender(clientUser); JOptionPane.showMessageDialog(null, From 0257db8449f1e35767f0839c4fbb679d0d9673c4 Mon Sep 17 00:00:00 2001 From: delvh Date: Sun, 9 Feb 2020 20:48:08 +0100 Subject: [PATCH 233/474] fixed Javadoc error. Current implementation is NOT working! --- src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java b/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java index 3322ce4..7c20760 100644 --- a/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java +++ b/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java @@ -3,7 +3,7 @@ package envoy.client.event; import envoy.event.Event; /** - * This {@link Event} indicates that a handshake completed successful + * This {@link Event} indicates that a handshake was completed successfully. * * Project: envoy-client
* File: HandshakeSuccessfulEvent.java
From eb00c1f389e71df7181f5a315d1c5d7ff30a0a7c Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Sun, 9 Feb 2020 22:15:15 +0100 Subject: [PATCH 234/474] Commented out the localDb client update stuff (temporary) --- src/main/java/envoy/client/ui/ChatWindow.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 206f670..a14a67d 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -401,6 +401,18 @@ public class ChatWindow extends JFrame { contactsModel.clear(); final java.util.List contacts = ((SearchResultEvent) evt).get(); logger.info("Received contact search result " + contacts); + + // // Checks whether a contact received from the server as search result already + // // exists in the contacts of this client. if so, it does not get added to the + // // contactsModel, and so can not be added to the contacts. + // for (int i = 0; i < contacts.size(); i++) { + // for (int j = 0; j < localDb.getUsers().size(); j++) { + // if (!(contacts.get(i).getId() == + // localDb.getUsers().get(contacts.get(i).getName()).getId())) { + // contactsModel.add(contacts.get(i)); + // } + // } + // } contacts.forEach(contactsModel::add); revalidate(); repaint(); From a93539ea062ae855b82dea316f15341f608ad72b Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Mon, 10 Feb 2020 19:51:50 +0100 Subject: [PATCH 235/474] Updated client * Updated ContactsRequest constructor to work with new versin of this event. *Implemented LocalDB updates when adding a contact and display it immediately, so you can chat directly. --- src/main/java/envoy/client/ui/ChatWindow.java | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index a14a67d..eed9ae9 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -262,7 +262,7 @@ public class ChatWindow extends JFrame { if (client.isOnline()) { try { if(!searchField.getText().isEmpty()) { - client.sendEvent(new ContactsRequest(searchField.getText())); + client.sendEvent(new ContactsRequest(searchField.getText(), client.getSender())); } else { contactsModel.clear(); revalidate(); @@ -279,7 +279,7 @@ public class ChatWindow extends JFrame { if (client.isOnline()) { try { if(!searchField.getText().isEmpty()) { - client.sendEvent(new ContactsRequest(searchField.getText())); + client.sendEvent(new ContactsRequest(searchField.getText(), client.getSender())); } } catch (IOException e1) { e1.printStackTrace(); @@ -401,18 +401,6 @@ public class ChatWindow extends JFrame { contactsModel.clear(); final java.util.List contacts = ((SearchResultEvent) evt).get(); logger.info("Received contact search result " + contacts); - - // // Checks whether a contact received from the server as search result already - // // exists in the contacts of this client. if so, it does not get added to the - // // contactsModel, and so can not be added to the contacts. - // for (int i = 0; i < contacts.size(); i++) { - // for (int j = 0; j < localDb.getUsers().size(); j++) { - // if (!(contacts.get(i).getId() == - // localDb.getUsers().get(contacts.get(i).getName()).getId())) { - // contactsModel.add(contacts.get(i)); - // } - // } - // } contacts.forEach(contactsModel::add); revalidate(); repaint(); @@ -427,13 +415,10 @@ public class ChatWindow extends JFrame { e.printStackTrace(); } - // TODO: Not finished LocalDB update of contact list - // Add this user to the chats - // userListModel.addElement(contact); - // Check if user exists in local DB - // if (localDb.getChats().stream().filter(c -> c.getRecipient().getId() == - // contact.getId()).count() == 0) - // localDb.getChats().add(new Chat(contact)); + // Update LocalDB + userListModel.addElement(contact); + localDb.getUsers().put(contact.getName(), contact); + localDb.getChats().add(new Chat(contact)); revalidate(); repaint(); From 78d8c08573f020fbd266d39dd8106308f7f2e0b6 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 10 Feb 2020 22:31:40 +0100 Subject: [PATCH 236/474] Refactored to the new contact related classes in envoy-common --- pom.xml | 2 +- .../envoy/client/event/AddContactEvent.java | 9 ++++---- src/main/java/envoy/client/ui/ChatWindow.java | 21 +++++++------------ .../client/ui/ContactsSearchRenderer.java | 11 ++-------- 4 files changed, 15 insertions(+), 28 deletions(-) diff --git a/pom.xml b/pom.xml index c7abb5f..0b5487d 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - f~contacts-SNAPSHOT + develop-SNAPSHOT diff --git a/src/main/java/envoy/client/event/AddContactEvent.java b/src/main/java/envoy/client/event/AddContactEvent.java index 8f356fa..087cfb3 100644 --- a/src/main/java/envoy/client/event/AddContactEvent.java +++ b/src/main/java/envoy/client/event/AddContactEvent.java @@ -1,14 +1,14 @@ package envoy.client.event; import envoy.data.User; -import envoy.event.ContactOperation.Operation; +import envoy.event.ContactOperationEvent.Operation; import envoy.event.Event; /** * Project: envoy-client
* File: AddContactEvent.java
* Created: 09.02.2020
- * + * * @author Maximilian Käfer * @since Envoy v0.3-alpha */ @@ -20,8 +20,8 @@ public class AddContactEvent implements Event { private static final long serialVersionUID = 7855669140917046709L; /** - * Initializes a {@link AddContactEvent} - * + * Initializes a {@link AddContactEvent}. + * * @param contact the user to be added to the contacts * @param operation the operation, which should be executed * @since Envoy v0.3-alpha @@ -38,5 +38,4 @@ public class AddContactEvent implements Event { * @return the operation, which should be executed */ public Operation getOperation() { return operation; } - } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index eed9ae9..07c26b1 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -26,7 +26,7 @@ import envoy.data.Message.MessageStatus; import envoy.data.MessageBuilder; import envoy.data.User; import envoy.event.*; -import envoy.event.ContactOperation.Operation; +import envoy.event.ContactOperationEvent.Operation; /** * Project: envoy-client
@@ -261,8 +261,8 @@ public class ChatWindow extends JFrame { public void removeUpdate(DocumentEvent e) { if (client.isOnline()) { try { - if(!searchField.getText().isEmpty()) { - client.sendEvent(new ContactsRequest(searchField.getText(), client.getSender())); + if (!searchField.getText().isEmpty()) { + client.sendEvent(new ContactSearchRequest(searchField.getText())); } else { contactsModel.clear(); revalidate(); @@ -278,9 +278,7 @@ public class ChatWindow extends JFrame { public void insertUpdate(DocumentEvent e) { if (client.isOnline()) { try { - if(!searchField.getText().isEmpty()) { - client.sendEvent(new ContactsRequest(searchField.getText(), client.getSender())); - } + if (!searchField.getText().isEmpty()) { client.sendEvent(new ContactSearchRequest(searchField.getText())); } } catch (IOException e1) { e1.printStackTrace(); } @@ -407,10 +405,10 @@ public class ChatWindow extends JFrame { }); EventBus.getInstance().register(AddContactEvent.class, (evt) -> { - User contact = ((AddContactEvent) evt).get(); - Operation operation = ((AddContactEvent) evt).getOperation(); + User contact = ((AddContactEvent) evt).get(); + Operation operation = ((AddContactEvent) evt).getOperation(); try { - client.sendEvent(new ContactOperation(contact, operation)); + client.sendEvent(new ContactOperationEvent(contact, operation)); } catch (IOException e) { e.printStackTrace(); } @@ -565,7 +563,6 @@ public class ChatWindow extends JFrame { contentPane.remove(scrollPane); contentPane.add(searchPane, gbc_searchPane); contentPane.revalidate(); - contactRenderer.setScrollPane(possibleContacts); contentPane.repaint(); } @@ -575,9 +572,7 @@ public class ChatWindow extends JFrame { * @param client the {@link Client} used to send and receive messages * @since Envoy v0.2-alpha */ - public void setClient(Client client) { - this.client = client; - } + public void setClient(Client client) { this.client = client; } /** * Sets the {@link LocalDb} used by this {@link ChatWindow}. After diff --git a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java index b435def..e346df8 100644 --- a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java @@ -11,7 +11,7 @@ import envoy.client.event.AddContactEvent; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; import envoy.data.User; -import envoy.event.ContactOperation.Operation; +import envoy.event.ContactOperationEvent; import envoy.event.EventBus; /** @@ -27,8 +27,6 @@ import envoy.event.EventBus; */ public class ContactsSearchRenderer implements ComponentListCellRenderer { - private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); - @Override public JComponent getListCellComponent(ComponentList list, User value, boolean isSelected) { final JPanel panel = new JPanel(); @@ -64,9 +62,7 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { add.setBackground(list.getBackground()); add.setForeground(list.getForeground()); - add.addActionListener((evt) -> { - EventBus.getInstance().dispatch(new AddContactEvent(value, Operation.ADD)); - }); + add.addActionListener((evt) -> { EventBus.getInstance().dispatch(new AddContactEvent(value, ContactOperationEvent.Operation.ADD)); }); panel.add(add); @@ -81,7 +77,4 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { return panel; } - - // TODO: Use this method properly - public void setScrollPane(PrimaryScrollPane scrollPane) { this.scrollPane = scrollPane; } } \ No newline at end of file From fa4cc8d6d92b402a5d93072a161dd72143560b05 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Mon, 10 Feb 2020 23:21:06 +0100 Subject: [PATCH 237/474] Small improvements * Resettings the searchField after adding a contact and clearing the contactsModel after adding a contact. * Revised LoginDialoge UI --- src/main/java/envoy/client/ui/ChatWindow.java | 4 + .../java/envoy/client/ui/LoginDialog.java | 85 ++++++++++++++++--- 2 files changed, 76 insertions(+), 13 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 07c26b1..c563144 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -413,6 +413,10 @@ public class ChatWindow extends JFrame { e.printStackTrace(); } + // Clearing the search field and the searchResultList + searchField.setText(""); + contactsModel.clear(); + // Update LocalDB userListModel.addElement(contact); localDb.getUsers().put(contact.getName(), contact); diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index d81ecc1..d8cd4ff 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -9,6 +9,7 @@ import java.util.Arrays; import javax.swing.*; import javax.swing.border.EmptyBorder; +import envoy.client.Settings; import envoy.data.LoginCredentials; /** @@ -22,19 +23,27 @@ import envoy.data.LoginCredentials; */ public class LoginDialog extends JDialog { - private final JPanel contentPanel = new JPanel(); - - private static final long serialVersionUID = 352021600833907468L; + private final JPanel contentPanel; private JTextField textField; private JPasswordField passwordField; - private JPasswordField repeatPasswordField; - private JLabel lblRepeatPassword; + + private JLabel lblUserName; + private JLabel lblPassword; + private JLabel lblRepeatPassword; + private GridBagConstraints gbc_lblRepeatPassword; private GridBagConstraints gbc_repeatPasswordField; + private JPanel buttonPane; + private JTextPane registerText; + private JCheckBox registerCheckBox; + private PrimaryButton okButton; + private PrimaryButton cancelButton; + private LoginCredentials credentials; + private static final long serialVersionUID = 352021600833907468L; /** * Displays a dialog enabling the user to enter their user name and password. * @@ -44,6 +53,7 @@ public class LoginDialog extends JDialog { setSize(338, 123); setLocationRelativeTo(null); getContentPane().setLayout(new BorderLayout()); + contentPanel = new JPanel(); contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); getContentPane().add(contentPanel, BorderLayout.CENTER); GridBagLayout gbl_contentPanel = new GridBagLayout(); @@ -53,7 +63,7 @@ public class LoginDialog extends JDialog { gbl_contentPanel.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE }; contentPanel.setLayout(gbl_contentPanel); { - JLabel lblUserName = new JLabel("User name:"); + lblUserName = new JLabel("Username:"); GridBagConstraints gbc_lblUserName = new GridBagConstraints(); gbc_lblUserName.anchor = GridBagConstraints.EAST; gbc_lblUserName.insets = new Insets(0, 0, 5, 5); @@ -63,6 +73,7 @@ public class LoginDialog extends JDialog { } { textField = new JTextField(); + textField.setBorder(null); GridBagConstraints gbc_textField = new GridBagConstraints(); gbc_textField.insets = new Insets(0, 0, 5, 0); gbc_textField.fill = GridBagConstraints.HORIZONTAL; @@ -72,7 +83,7 @@ public class LoginDialog extends JDialog { textField.setColumns(10); } { - JLabel lblPassword = new JLabel("Password:"); + lblPassword = new JLabel("Password:"); GridBagConstraints gbc_lblPassword = new GridBagConstraints(); gbc_lblPassword.anchor = GridBagConstraints.EAST; gbc_lblPassword.insets = new Insets(0, 0, 0, 5); @@ -82,6 +93,7 @@ public class LoginDialog extends JDialog { } { passwordField = new JPasswordField(); + passwordField.setBorder(null); GridBagConstraints gbc_passwordField = new GridBagConstraints(); gbc_passwordField.fill = GridBagConstraints.HORIZONTAL; gbc_passwordField.gridx = 1; @@ -98,21 +110,23 @@ public class LoginDialog extends JDialog { } { repeatPasswordField = new JPasswordField(); + repeatPasswordField.setBorder(null); gbc_repeatPasswordField = new GridBagConstraints(); gbc_repeatPasswordField.fill = GridBagConstraints.HORIZONTAL; gbc_repeatPasswordField.gridx = 1; gbc_repeatPasswordField.gridy = 2; } { - JPanel buttonPane = new JPanel(); + buttonPane = new JPanel(); - JTextPane registerText = new JTextPane(); + registerText = new JTextPane(); + registerText.setEditable(false); registerText.setText("Register?"); registerText.setFont(new Font("Arial", Font.BOLD, 12)); registerText.setAlignmentX(LEFT_ALIGNMENT); buttonPane.add(registerText); - JCheckBox registerCheckBox = new JCheckBox(); + registerCheckBox = new JCheckBox(); registerCheckBox.setAlignmentX(LEFT_ALIGNMENT); registerCheckBox.addItemListener(new ItemListener() { @@ -122,7 +136,7 @@ public class LoginDialog extends JDialog { case ItemEvent.SELECTED: contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword); contentPanel.add(repeatPasswordField, gbc_repeatPasswordField); - setSize(338, 160); + setSize(338, 148); contentPanel.revalidate(); contentPanel.repaint(); break; @@ -144,7 +158,7 @@ public class LoginDialog extends JDialog { buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); getContentPane().add(buttonPane, BorderLayout.SOUTH); { - JButton okButton = new JButton("OK"); + okButton = new PrimaryButton("OK"); okButton.addActionListener((evt) -> { try { if (registerCheckBox.isSelected()) { @@ -169,17 +183,62 @@ public class LoginDialog extends JDialog { getRootPane().setDefaultButton(okButton); } { - JButton cancelButton = new JButton("Cancel"); + cancelButton = new PrimaryButton("Cancel"); cancelButton.addActionListener((evt) -> dispose()); cancelButton.setActionCommand("Cancel"); buttonPane.add(cancelButton); } } + setTheme(); setModal(true); setVisible(true); } + private void setTheme() { + Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + + // Panels + contentPanel.setBackground(theme.getBackgroundColor()); + contentPanel.setForeground(theme.getBackgroundColor()); + + buttonPane.setBackground(theme.getBackgroundColor()); + buttonPane.setForeground(theme.getBackgroundColor()); + + // Input Fields + textField.setBackground(theme.getCellColor()); + textField.setForeground(theme.getUserNameColor()); + + passwordField.setBackground(theme.getCellColor()); + passwordField.setForeground(theme.getUserNameColor()); + + repeatPasswordField.setBackground(theme.getCellColor()); + repeatPasswordField.setForeground(theme.getUserNameColor()); + + // JLabels + lblUserName.setBackground(theme.getCellColor()); + lblUserName.setForeground(theme.getUserNameColor()); + + lblPassword.setBackground(theme.getCellColor()); + lblPassword.setForeground(theme.getUserNameColor()); + + lblRepeatPassword.setBackground(theme.getCellColor()); + lblRepeatPassword.setForeground(theme.getUserNameColor()); + + // Register + registerText.setBackground(theme.getCellColor()); + registerText.setForeground(theme.getUserNameColor()); + + registerCheckBox.setBackground(theme.getCellColor()); + + // Buttons + okButton.setBackground(theme.getInteractableBackgroundColor()); + okButton.setForeground(theme.getInteractableForegroundColor()); + + cancelButton.setBackground(theme.getInteractableBackgroundColor()); + cancelButton.setForeground(theme.getInteractableForegroundColor()); + } + /** * @return the {@link LoginCredentials} entered by the user, or {@code null} if * the dialog has been cancelled From c0954036a5b361eea4472db35524582cf5f7d624 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 11 Feb 2020 17:17:22 +0100 Subject: [PATCH 238/474] Adjusted to event system refactoring --- .settings/org.eclipse.jdt.core.prefs | 5 ++- .../envoy/client/event/AddContactEvent.java | 41 ------------------- .../client/event/MessageCreationEvent.java | 3 +- .../java/envoy/client/event/MessageEvent.java | 34 --------------- .../event/MessageModificationEvent.java | 3 +- .../envoy/client/event/SearchResultEvent.java | 32 --------------- .../envoy/client/event/ThemeChangeEvent.java | 8 +--- src/main/java/envoy/client/net/Client.java | 3 +- src/main/java/envoy/client/net/Receiver.java | 1 - src/main/java/envoy/client/ui/ChatWindow.java | 19 +++++---- .../client/ui/ContactsSearchRenderer.java | 3 +- 11 files changed, 21 insertions(+), 131 deletions(-) delete mode 100644 src/main/java/envoy/client/event/AddContactEvent.java delete mode 100644 src/main/java/envoy/client/event/MessageEvent.java delete mode 100644 src/main/java/envoy/client/event/SearchResultEvent.java diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 64c8c95..cbcb911 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -92,12 +92,13 @@ org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled -org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning @@ -126,4 +127,4 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.8 \ No newline at end of file +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/src/main/java/envoy/client/event/AddContactEvent.java b/src/main/java/envoy/client/event/AddContactEvent.java deleted file mode 100644 index 087cfb3..0000000 --- a/src/main/java/envoy/client/event/AddContactEvent.java +++ /dev/null @@ -1,41 +0,0 @@ -package envoy.client.event; - -import envoy.data.User; -import envoy.event.ContactOperationEvent.Operation; -import envoy.event.Event; - -/** - * Project: envoy-client
- * File: AddContactEvent.java
- * Created: 09.02.2020
- * - * @author Maximilian Käfer - * @since Envoy v0.3-alpha - */ -public class AddContactEvent implements Event { - - private User contact; - private Operation operation; - - private static final long serialVersionUID = 7855669140917046709L; - - /** - * Initializes a {@link AddContactEvent}. - * - * @param contact the user to be added to the contacts - * @param operation the operation, which should be executed - * @since Envoy v0.3-alpha - */ - public AddContactEvent(User contact, Operation operation) { - this.contact = contact; - this.operation = operation; - } - - @Override - public User get() { return contact; } - - /** - * @return the operation, which should be executed - */ - public Operation getOperation() { return operation; } -} diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java index 72e47f5..4781943 100644 --- a/src/main/java/envoy/client/event/MessageCreationEvent.java +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -1,6 +1,7 @@ package envoy.client.event; import envoy.data.Message; +import envoy.event.Event; /** * Project: envoy-client
@@ -10,7 +11,7 @@ import envoy.data.Message; * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha */ -public class MessageCreationEvent extends MessageEvent { +public class MessageCreationEvent extends Event { private static final long serialVersionUID = -6451021678064566774L; diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java deleted file mode 100644 index fb50109..0000000 --- a/src/main/java/envoy/client/event/MessageEvent.java +++ /dev/null @@ -1,34 +0,0 @@ -package envoy.client.event; - -import envoy.data.Message; -import envoy.event.Event; - -/** - * Project: envoy-client
- * File: MessageCreationEvent.java
- * Created: 4 Dec 2019
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha - */ -public class MessageEvent implements Event { - - private static final long serialVersionUID = 7658989461923112804L; - - /** - * the {@link Message} attached to this {@link MessageEvent}. - */ - protected final Message message; - - /** - * Initializes a {@link MessageEvent} conveying information about a - * {@link Message} object. - * - * @param message the {@link Message} object to attach to this event - * @since Envoy v0.2-alpha - */ - public MessageEvent(Message message) { this.message = message; } - - @Override - public Message get() { return message; } -} diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java index 4077383..8ddaaf0 100644 --- a/src/main/java/envoy/client/event/MessageModificationEvent.java +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -1,6 +1,7 @@ package envoy.client.event; import envoy.data.Message; +import envoy.event.Event; /** * Project: envoy-client
@@ -10,7 +11,7 @@ import envoy.data.Message; * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha */ -public class MessageModificationEvent extends MessageEvent { +public class MessageModificationEvent extends Event { private static final long serialVersionUID = 4650039506439563116L; diff --git a/src/main/java/envoy/client/event/SearchResultEvent.java b/src/main/java/envoy/client/event/SearchResultEvent.java deleted file mode 100644 index dc834d3..0000000 --- a/src/main/java/envoy/client/event/SearchResultEvent.java +++ /dev/null @@ -1,32 +0,0 @@ -package envoy.client.event; - -import java.util.List; - -import envoy.data.User; -import envoy.event.Event; - -/** - * Project: envoy-client
- * File: SearchResultEvent.java
- * Created: 08.02.2020
- * - * @author Maximilian Käfer - * @since Envoy v0.3-alpha - */ -public class SearchResultEvent implements Event> { - - private final List resultList; - - private static final long serialVersionUID = 2540321329192201277L; - - /** - * Initializes a {@link SearchResultEvent} - * - * @param resultList the List containing the contacts sent from the server - * @since Envoy v0.3-alpha - */ - public SearchResultEvent(List resultList) { this.resultList = resultList; } - - @Override - public List get() { return resultList; } -} diff --git a/src/main/java/envoy/client/event/ThemeChangeEvent.java b/src/main/java/envoy/client/event/ThemeChangeEvent.java index 02a15df..c164f72 100644 --- a/src/main/java/envoy/client/event/ThemeChangeEvent.java +++ b/src/main/java/envoy/client/event/ThemeChangeEvent.java @@ -11,10 +11,9 @@ import envoy.event.Event; * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha */ -public class ThemeChangeEvent implements Event { +public class ThemeChangeEvent extends Event { private static final long serialVersionUID = 6756772448803774547L; - private final Theme theme; /** * Initializes a {@link ThemeChangeEvent} conveying information about the change @@ -23,8 +22,5 @@ public class ThemeChangeEvent implements Event { * @param theme the new currently used {@link Theme} object * @since Envoy v0.2-alpha */ - public ThemeChangeEvent(Theme theme) { this.theme = theme; } - - @Override - public Theme get() { return theme; } + public ThemeChangeEvent(Theme theme) { super(theme); } } diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index fec5570..550b7f2 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -12,7 +12,6 @@ import javax.naming.TimeLimitExceededException; import envoy.client.data.Cache; import envoy.client.data.Config; import envoy.client.data.LocalDb; -import envoy.client.event.SearchResultEvent; import envoy.client.util.EnvoyLog; import envoy.data.*; import envoy.event.*; @@ -115,7 +114,7 @@ public class Client implements Closeable { receiver.registerProcessor(IdGenerator.class, localDb::setIdGenerator); // Process contact searches - receiver.registerProcessor(Contacts.class, contacts -> EventBus.getInstance().dispatch(new SearchResultEvent(contacts.getContacts()))); + receiver.registerProcessor(ContactSearchResult.class, EventBus.getInstance()::dispatch); // Request a generator if none is present or the existing one is consumed if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator(); diff --git a/src/main/java/envoy/client/net/Receiver.java b/src/main/java/envoy/client/net/Receiver.java index 5030241..25e7153 100644 --- a/src/main/java/envoy/client/net/Receiver.java +++ b/src/main/java/envoy/client/net/Receiver.java @@ -35,7 +35,6 @@ public class Receiver implements Runnable { */ public Receiver(InputStream in) { this.in = in; } - @SuppressWarnings("unchecked") @Override public void run() { diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index f5400a3..5a0898f 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -4,6 +4,7 @@ import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.IOException; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -15,7 +16,8 @@ import javax.swing.event.DocumentListener; import envoy.client.Settings; import envoy.client.data.Chat; import envoy.client.data.LocalDb; -import envoy.client.event.*; +import envoy.client.event.MessageCreationEvent; +import envoy.client.event.ThemeChangeEvent; import envoy.client.net.Client; import envoy.client.net.WriteProxy; import envoy.client.ui.list.ComponentList; @@ -27,7 +29,6 @@ import envoy.data.Message.MessageStatus; import envoy.data.MessageBuilder; import envoy.data.User; import envoy.event.*; -import envoy.event.ContactOperationEvent.Operation; /** * Project: envoy-client
@@ -189,7 +190,6 @@ public class ChatWindow extends JFrame { userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); userList.addListSelectionListener((listSelectionEvent) -> { if (client != null && localDb != null && !listSelectionEvent.getValueIsAdjusting()) { - @SuppressWarnings("unchecked") final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); @@ -400,24 +400,25 @@ public class ChatWindow extends JFrame { repaint(); }); - EventBus.getInstance().register(SearchResultEvent.class, (evt) -> { + EventBus.getInstance().register(ContactSearchResult.class, (evt) -> { contactsModel.clear(); - final java.util.List contacts = ((SearchResultEvent) evt).get(); + final java.util.List contacts = (List) evt.get(); logger.info("Received contact search result " + contacts); contacts.forEach(contactsModel::add); revalidate(); repaint(); }); - EventBus.getInstance().register(AddContactEvent.class, (evt) -> { - User contact = ((AddContactEvent) evt).get(); - Operation operation = ((AddContactEvent) evt).getOperation(); + EventBus.getInstance().register(ContactOperationEvent.class, (evt) -> { + try { - client.sendEvent(new ContactOperationEvent(contact, operation)); + client.sendEvent(evt); } catch (IOException e) { e.printStackTrace(); } + User contact = (User) evt.get(); + // Clearing the search field and the searchResultList searchField.setText(""); contactsModel.clear(); diff --git a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java index e346df8..c469475 100644 --- a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java @@ -7,7 +7,6 @@ import java.awt.Font; import javax.swing.*; import envoy.client.Settings; -import envoy.client.event.AddContactEvent; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; import envoy.data.User; @@ -62,7 +61,7 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { add.setBackground(list.getBackground()); add.setForeground(list.getForeground()); - add.addActionListener((evt) -> { EventBus.getInstance().dispatch(new AddContactEvent(value, ContactOperationEvent.Operation.ADD)); }); + add.addActionListener((evt) -> { EventBus.getInstance().dispatch(new ContactOperationEvent(value, ContactOperationEvent.Operation.ADD)); }); panel.add(add); From 5a718aa1c9492ae0f85de5671cb0aadd81df5a8d Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Tue, 11 Feb 2020 18:15:15 +0100 Subject: [PATCH 239/474] Implemented contact list update --- .../java/envoy/client/event/SendEvent.java | 23 +++++++++++++++++++ src/main/java/envoy/client/net/Client.java | 14 +++++++++++ src/main/java/envoy/client/ui/ChatWindow.java | 6 ----- .../client/ui/ContactsSearchRenderer.java | 7 +++++- 4 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 src/main/java/envoy/client/event/SendEvent.java diff --git a/src/main/java/envoy/client/event/SendEvent.java b/src/main/java/envoy/client/event/SendEvent.java new file mode 100644 index 0000000..2d95fc8 --- /dev/null +++ b/src/main/java/envoy/client/event/SendEvent.java @@ -0,0 +1,23 @@ +package envoy.client.event; + +import envoy.event.Event; + +/** + * Project: envoy-client
+ * File: SendEvent.java
+ * Created: 11.02.2020
+ * + * @author: Maximilian Käfer + * + * @since Envoy v0.3-alpha + */ +public class SendEvent extends Event> { + + private static final long serialVersionUID = 8372746924138839060L; + + /** + * @param value the event to send to the server + */ + public SendEvent(Event value) { super(value); } + +} diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 550b7f2..b9985c1 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -12,9 +12,11 @@ import javax.naming.TimeLimitExceededException; import envoy.client.data.Cache; import envoy.client.data.Config; import envoy.client.data.LocalDb; +import envoy.client.event.SendEvent; import envoy.client.util.EnvoyLog; import envoy.data.*; import envoy.event.*; +import envoy.event.ContactOperationEvent.Operation; import envoy.util.SerializationUtils; /** @@ -116,6 +118,18 @@ public class Client implements Closeable { // Process contact searches receiver.registerProcessor(ContactSearchResult.class, EventBus.getInstance()::dispatch); + receiver.registerProcessor(Contacts.class, + contacts -> EventBus.getInstance().dispatch(new ContactOperationEvent(contacts.getContacts().get(0), Operation.ADD))); + + // Send event + EventBus.getInstance().register(SendEvent.class, evt -> { + try { + sendEvent(((SendEvent) evt).get()); + } catch (IOException e) { + e.printStackTrace(); + } + }); + // Request a generator if none is present or the existing one is consumed if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator(); } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 5a0898f..a278325 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -411,12 +411,6 @@ public class ChatWindow extends JFrame { EventBus.getInstance().register(ContactOperationEvent.class, (evt) -> { - try { - client.sendEvent(evt); - } catch (IOException e) { - e.printStackTrace(); - } - User contact = (User) evt.get(); // Clearing the search field and the searchResultList diff --git a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java index c469475..078e289 100644 --- a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java @@ -7,6 +7,7 @@ import java.awt.Font; import javax.swing.*; import envoy.client.Settings; +import envoy.client.event.SendEvent; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; import envoy.data.User; @@ -61,7 +62,11 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { add.setBackground(list.getBackground()); add.setForeground(list.getForeground()); - add.addActionListener((evt) -> { EventBus.getInstance().dispatch(new ContactOperationEvent(value, ContactOperationEvent.Operation.ADD)); }); + add.addActionListener(evt -> { + ContactOperationEvent contactsOperationEvent = new ContactOperationEvent(value, ContactOperationEvent.Operation.ADD); + EventBus.getInstance().dispatch(contactsOperationEvent); + EventBus.getInstance().dispatch(new SendEvent(contactsOperationEvent)); + }); panel.add(add); From 8667409413a03510818c448a7db93c7bd331b64b Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 11 Feb 2020 19:35:23 +0100 Subject: [PATCH 240/474] Cleanup, fixed offline cache relay when starting in offline mode --- src/main/java/envoy/client/Settings.java | 3 -- src/main/java/envoy/client/ui/ChatWindow.java | 46 +++++++------------ .../client/ui/ContactsSearchRenderer.java | 16 ++----- src/main/java/envoy/client/ui/Startup.java | 2 +- 4 files changed, 23 insertions(+), 44 deletions(-) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index efb03d6..c921605 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -127,7 +127,6 @@ public class Settings { * @param themeName the name to set * @since Envoy v0.2-alpha */ - @SuppressWarnings("unchecked") public void setCurrentTheme(String themeName) { ((SettingsItem) items.get("currentTheme")).set(themeName); } /** @@ -146,7 +145,6 @@ public class Settings { * conjunction with the {@code Control} key. * @since Envoy v0.2-alpha */ - @SuppressWarnings("unchecked") public void setEnterToSend(boolean enterToSend) { ((SettingsItem) items.get("enterToSend")).set(enterToSend); } /** @@ -161,7 +159,6 @@ public class Settings { * @param currentOnCloseMode the on close mode that should be set. * @since Envoy v0.3-alpha */ - @SuppressWarnings("unchecked") public void setCurrentOnCloseMode(boolean currentOnCloseMode) { ((SettingsItem) items.get("onCloseMode")).set(currentOnCloseMode); } /** diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index a278325..17c0583 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -103,11 +103,6 @@ public class ChatWindow extends JFrame { gbl_contentPane.rowWeights = new double[] { 0.03, 0.001, 1.0, 0.005 }; contentPane.setLayout(gbl_contentPane); - // TODO: messageList.setFocusTraversalKeysEnabled(false); - // messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); - - // messageList.setFont(new Font("Arial", Font.PLAIN, 17)); - // messageList.setFixedCellHeight(60); messageList.setBorder(new EmptyBorder(space, space, space, space)); scrollPane.setViewportView(messageList); @@ -164,14 +159,7 @@ public class ChatWindow extends JFrame { gbc_moveSelectionSettingsButton.insets = insets; - settingsButton.addActionListener((evt) -> { - try { - new SettingsScreen().setVisible(true); - } catch (Exception e) { - logger.log(Level.WARNING, "An error occured while opening the settings screen", e); - e.printStackTrace(); - } - }); + settingsButton.addActionListener(evt -> new SettingsScreen().setVisible(true)); contentPane.add(settingsButton, gbc_moveSelectionSettingsButton); // Partner name display @@ -260,35 +248,35 @@ public class ChatWindow extends JFrame { searchField.getDocument().addDocumentListener(new DocumentListener() { @Override - public void removeUpdate(DocumentEvent e) { + public void removeUpdate(DocumentEvent evt) { if (client.isOnline()) { - try { - if (!searchField.getText().isEmpty()) { + if (searchField.getText().isEmpty()) { + contactsModel.clear(); + revalidate(); + repaint(); + } else { + try { client.sendEvent(new ContactSearchRequest(searchField.getText())); - } else { - contactsModel.clear(); - revalidate(); - repaint(); + } catch (IOException e) { + e.printStackTrace(); } - } catch (IOException e1) { - e1.printStackTrace(); } } } @Override - public void insertUpdate(DocumentEvent e) { + public void insertUpdate(DocumentEvent evt) { if (client.isOnline()) { try { - if (!searchField.getText().isEmpty()) { client.sendEvent(new ContactSearchRequest(searchField.getText())); } - } catch (IOException e1) { - e1.printStackTrace(); + client.sendEvent(new ContactSearchRequest(searchField.getText())); + } catch (IOException e) { + e.printStackTrace(); } } } @Override - public void changedUpdate(DocumentEvent e) {} + public void changedUpdate(DocumentEvent evt) {} }); GridBagConstraints gbc_cancelButton = new GridBagConstraints(); @@ -316,7 +304,6 @@ public class ChatWindow extends JFrame { searchPane.add(possibleContacts, gbc_possibleContacts); // Contacts Header - GridBagConstraints gbc_contactsHeader = new GridBagConstraints(); gbc_contactsHeader.fill = GridBagConstraints.BOTH; gbc_contactsHeader.gridx = 0; @@ -400,6 +387,7 @@ public class ChatWindow extends JFrame { repaint(); }); + // Listen to contact search results EventBus.getInstance().register(ContactSearchResult.class, (evt) -> { contactsModel.clear(); final java.util.List contacts = (List) evt.get(); @@ -409,8 +397,8 @@ public class ChatWindow extends JFrame { repaint(); }); + // Add new contacts to the contact list EventBus.getInstance().register(ContactOperationEvent.class, (evt) -> { - User contact = (User) evt.get(); // Clearing the search field and the searchResultList diff --git a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java index 078e289..f206c54 100644 --- a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java @@ -28,26 +28,20 @@ import envoy.event.EventBus; public class ContactsSearchRenderer implements ComponentListCellRenderer { @Override - public JComponent getListCellComponent(ComponentList list, User value, boolean isSelected) { + public JComponent getListCellComponent(ComponentList list, User user, boolean isSelected) { final JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); if (isSelected) { panel.setBackground(Color.DARK_GRAY); panel.setForeground(Color.RED); - } else { panel.setBackground(list.getBackground()); panel.setForeground(list.getForeground()); } - // TODO: Handle message attachments - - final String text = value.getName(); - - // Getting the UserColor in the Chat of the current theme - String textColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat().toHex(); - - JLabel display = new JLabel(String.format("

%s", textColor, text)); + JLabel display = new JLabel(String.format("

%s", + Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat().toHex(), + user.getName())); display.setAlignmentX(Component.LEFT_ALIGNMENT); display.setAlignmentY(Component.CENTER_ALIGNMENT); display.setFont(new Font("Arial", Font.PLAIN, 16)); @@ -63,7 +57,7 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { add.setForeground(list.getForeground()); add.addActionListener(evt -> { - ContactOperationEvent contactsOperationEvent = new ContactOperationEvent(value, ContactOperationEvent.Operation.ADD); + ContactOperationEvent contactsOperationEvent = new ContactOperationEvent(user, ContactOperationEvent.Operation.ADD); EventBus.getInstance().dispatch(contactsOperationEvent); EventBus.getInstance().dispatch(new SendEvent(contactsOperationEvent)); }); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index a976824..706e030 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -163,7 +163,7 @@ public class Startup { chatWindow.initContent(client, localDb, writeProxy); // Relay unread messages from cache - if (cache != null) cache.relay(); + if (cache != null && client.isOnline()) cache.relay(); try { new StatusTrayIcon(chatWindow).show(); From 836f0c39b8a7014f14853f9026f5b78b27407ed7 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 12 Feb 2020 06:12:04 +0100 Subject: [PATCH 241/474] Removed event handler casts, simplified logging statements --- src/main/java/envoy/client/net/Client.java | 4 ++-- .../MessageStatusChangeEventProcessor.java | 5 +--- .../client/net/ReceivedMessageProcessor.java | 1 - .../client/net/UserStatusChangeProcessor.java | 15 ++++-------- .../java/envoy/client/net/WriteProxy.java | 4 ++-- src/main/java/envoy/client/ui/ChatWindow.java | 23 +++++++++---------- .../java/envoy/client/ui/StatusTrayIcon.java | 7 ++---- .../client/ui/settings/SettingsScreen.java | 2 +- .../ui/settings/ThemeCustomizationPanel.java | 14 +++++------ 9 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index b9985c1..8a62925 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -110,7 +110,7 @@ public class Client implements Closeable { receiver.registerProcessor(MessageStatusChangeEvent.class, new MessageStatusChangeEventProcessor()); // Process user status changes - receiver.registerProcessor(UserStatusChangeEvent.class, new UserStatusChangeProcessor(this)); + receiver.registerProcessor(UserStatusChangeEvent.class, new UserStatusChangeProcessor(localDb)); // Process message ID generation receiver.registerProcessor(IdGenerator.class, localDb::setIdGenerator); @@ -124,7 +124,7 @@ public class Client implements Closeable { // Send event EventBus.getInstance().register(SendEvent.class, evt -> { try { - sendEvent(((SendEvent) evt).get()); + sendEvent(evt.get()); } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java index 1cf457f..b81561c 100644 --- a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java +++ b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java @@ -30,9 +30,6 @@ public class MessageStatusChangeEventProcessor implements Consumer { @Override public void accept(Message message) { - logger.info("Received message object " + message); if (message.getStatus() != MessageStatus.SENT) logger.warning("The message has the unexpected status " + message.getStatus()); else { // Update status to RECEIVED diff --git a/src/main/java/envoy/client/net/UserStatusChangeProcessor.java b/src/main/java/envoy/client/net/UserStatusChangeProcessor.java index 744e6e8..69a36d4 100644 --- a/src/main/java/envoy/client/net/UserStatusChangeProcessor.java +++ b/src/main/java/envoy/client/net/UserStatusChangeProcessor.java @@ -1,9 +1,8 @@ package envoy.client.net; import java.util.function.Consumer; -import java.util.logging.Logger; -import envoy.client.util.EnvoyLog; +import envoy.client.data.LocalDb; import envoy.event.EventBus; import envoy.event.UserStatusChangeEvent; @@ -17,21 +16,17 @@ import envoy.event.UserStatusChangeEvent; */ public class UserStatusChangeProcessor implements Consumer { - private Client client; - - private static final Logger logger = EnvoyLog.getLogger(UserStatusChangeProcessor.class.getSimpleName()); + private final LocalDb localDb; /** - * @param client the {@link Client} who receives an - * {@link UserStatusChangeEvent} + * @param localDb the local database in which status updates will by applied * @since Envoy v0.3-alpha */ - public UserStatusChangeProcessor(Client client) { this.client = client; } + public UserStatusChangeProcessor(LocalDb localDb) { this.localDb = localDb; } @Override public void accept(UserStatusChangeEvent evt) { - logger.info("Received " + evt); - client.getContacts().getContacts().stream().filter((user) -> user.getId() == evt.getId()).findFirst().get().setStatus(evt.get()); + localDb.getUsers().values().stream().filter(u -> u.getId() == evt.getId()).findFirst().get().setStatus(evt.get()); EventBus.getInstance().dispatch(evt); } } diff --git a/src/main/java/envoy/client/net/WriteProxy.java b/src/main/java/envoy/client/net/WriteProxy.java index 98206ae..93e67d8 100644 --- a/src/main/java/envoy/client/net/WriteProxy.java +++ b/src/main/java/envoy/client/net/WriteProxy.java @@ -45,12 +45,14 @@ public class WriteProxy { // Initialize cache processors for messages and message status change events localDb.getMessageCache().setProcessor(msg -> { try { + logger.info("Sending cached " + msg); client.sendMessage(msg); } catch (IOException e) { logger.log(Level.SEVERE, "Could not send cached message", e); } }); localDb.getStatusCache().setProcessor(evt -> { + logger.info("Sending cached " + evt); try { client.sendEvent(evt); } catch (IOException e) { @@ -66,8 +68,6 @@ public class WriteProxy { * @since Envoy v0.3-alpha */ public void flushCache() { - logger.info("Sending cached messages and message status change events..."); - // Send messages localDb.getMessageCache().relay(); diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 17c0583..5aa18c5 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -4,7 +4,6 @@ import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.IOException; -import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -346,14 +345,14 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); // Listen to theme changes - EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get())); + EventBus.getInstance().register(ThemeChangeEvent.class, evt -> applyTheme(evt.get())); // Listen to user status changes - EventBus.getInstance().register(UserStatusChangeEvent.class, (evt) -> { userList.revalidate(); userList.repaint(); }); + EventBus.getInstance().register(UserStatusChangeEvent.class, evt -> { userList.revalidate(); userList.repaint(); }); // Listen to received messages - EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { - Message message = ((MessageCreationEvent) evt).get(); + EventBus.getInstance().register(MessageCreationEvent.class, evt -> { + Message message = evt.get(); Chat chat = localDb.getChats().stream().filter(c -> c.getRecipient().getId() == message.getSenderId()).findFirst().get(); chat.appendMessage(message); @@ -365,9 +364,9 @@ public class ChatWindow extends JFrame { }); // Listen to message status changes - EventBus.getInstance().register(MessageStatusChangeEvent.class, (evt) -> { - final long id = ((MessageStatusChangeEvent) evt).getId(); - final MessageStatus status = (MessageStatus) evt.get(); + EventBus.getInstance().register(MessageStatusChangeEvent.class, evt -> { + final long id = evt.getId(); + final MessageStatus status = evt.get(); for (Chat c : localDb.getChats()) for (Message m : c.getModel()) @@ -388,9 +387,9 @@ public class ChatWindow extends JFrame { }); // Listen to contact search results - EventBus.getInstance().register(ContactSearchResult.class, (evt) -> { + EventBus.getInstance().register(ContactSearchResult.class, evt -> { contactsModel.clear(); - final java.util.List contacts = (List) evt.get(); + final java.util.List contacts = evt.get(); logger.info("Received contact search result " + contacts); contacts.forEach(contactsModel::add); revalidate(); @@ -398,8 +397,8 @@ public class ChatWindow extends JFrame { }); // Add new contacts to the contact list - EventBus.getInstance().register(ContactOperationEvent.class, (evt) -> { - User contact = (User) evt.get(); + EventBus.getInstance().register(ContactOperationEvent.class, evt -> { + User contact = evt.get(); // Clearing the search field and the searchResultList searchField.setText(""); diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 0cfda6a..4513aea 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -74,13 +74,10 @@ public class StatusTrayIcon { trayIcon.addActionListener((evt) -> { focusTarget.setVisible(true); focusTarget.requestFocus(); }); // Start processing message events + // TODO: Handle other message types EventBus.getInstance() .register(MessageCreationEvent.class, - (evt) -> { - // TODO: Handle other message types - if (displayMessages) - trayIcon.displayMessage("New message received", ((MessageCreationEvent) evt).get().getText(), MessageType.INFO); - }); + evt -> { if (displayMessages) trayIcon.displayMessage("New message received", evt.get().getText(), MessageType.INFO); }); } /** diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 533200f..af68e8e 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -159,7 +159,7 @@ public class SettingsScreen extends JDialog { applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); // Respond to theme changes - EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme(((ThemeChangeEvent) evt).get())); + EventBus.getInstance().register(ThemeChangeEvent.class, evt -> applyTheme(evt.get())); setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); setModal(true); diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 9d4c6be..8df3491 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -47,7 +47,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { * Initializes a {@link ThemeCustomizationPanel} that enables the user to change * the current {@link Theme} and create new themes as part of the * {@link SettingsScreen}. - * + * * @param parent the {@link SettingsScreen} as a part of which this * {@link SettingsPanel} is displayed * @since Envoy v0.2-alpha @@ -119,8 +119,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { // Respond to theme changes EventBus.getInstance() .register(ThemeChangeEvent.class, - (evt) -> { - final Theme currentTheme = ((ThemeChangeEvent) evt).get(); + evt -> { + final Theme currentTheme = evt.get(); temporaryTheme = new Theme("temporaryTheme", currentTheme); applyTheme(currentTheme); }); @@ -130,7 +130,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { public ActionListener getOkButtonAction() { return (evt) -> { if (themeChanged) { - new NewThemeScreen(parent, (name) -> { + new NewThemeScreen(parent, name -> { // Create new theme logger.log(Level.FINEST, name); Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); @@ -140,12 +140,12 @@ public class ThemeCustomizationPanel extends SettingsPanel { // Select new theme name themes.setSelectedIndex(themesModel.getSize() - 1); - }, (name) -> { + }, name -> { // Modify theme Settings.getInstance().getThemes().replace(name, new Theme(name, temporaryTheme)); - if(themes.getSelectedItem().equals(name)) { + if (themes.getSelectedItem().equals(name)) { EventBus.getInstance().dispatch(new ThemeChangeEvent(Settings.getInstance().getTheme(name))); - }else { + } else { themes.setSelectedItem(name); } }).setVisible(true); From 511146c98eeb037c858cebc544777206d54becb6 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 12 Feb 2020 07:12:22 +0100 Subject: [PATCH 242/474] Clean-up, moved Settings and SettingsItem into the data package --- .../envoy/client/{ => data}/Settings.java | 3 +- .../envoy/client/{ => data}/SettingsItem.java | 2 +- .../event/HandshakeSuccessfulEvent.java | 2 +- src/main/java/envoy/client/ui/ChatWindow.java | 2 +- .../client/ui/ContactsSearchRenderer.java | 2 +- .../java/envoy/client/ui/LoginDialog.java | 29 ++++++++++--------- .../envoy/client/ui/MessageListRenderer.java | 2 +- .../envoy/client/ui/PrimaryScrollBar.java | 2 +- .../envoy/client/ui/PrimaryToggleSwitch.java | 4 +-- src/main/java/envoy/client/ui/Startup.java | 3 +- .../envoy/client/ui/UserListRenderer.java | 2 +- .../ui/settings/GeneralSettingsPanel.java | 4 +-- .../client/ui/settings/NewThemeScreen.java | 2 +- .../client/ui/settings/SettingsScreen.java | 2 +- .../ui/settings/ThemeCustomizationPanel.java | 2 +- 15 files changed, 31 insertions(+), 32 deletions(-) rename src/main/java/envoy/client/{ => data}/Settings.java (99%) rename src/main/java/envoy/client/{ => data}/SettingsItem.java (99%) diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/data/Settings.java similarity index 99% rename from src/main/java/envoy/client/Settings.java rename to src/main/java/envoy/client/data/Settings.java index c921605..8cf0283 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/data/Settings.java @@ -1,4 +1,4 @@ -package envoy.client; +package envoy.client.data; import java.io.File; import java.io.IOException; @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; -import envoy.client.data.Config; import envoy.client.ui.Color; import envoy.client.ui.Theme; import envoy.util.SerializationUtils; diff --git a/src/main/java/envoy/client/SettingsItem.java b/src/main/java/envoy/client/data/SettingsItem.java similarity index 99% rename from src/main/java/envoy/client/SettingsItem.java rename to src/main/java/envoy/client/data/SettingsItem.java index 4de2a47..57ba600 100644 --- a/src/main/java/envoy/client/SettingsItem.java +++ b/src/main/java/envoy/client/data/SettingsItem.java @@ -1,4 +1,4 @@ -package envoy.client; +package envoy.client.data; import java.io.Serializable; import java.util.HashMap; diff --git a/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java b/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java index 7c20760..9cafa48 100644 --- a/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java +++ b/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java @@ -12,7 +12,7 @@ import envoy.event.Event; * @author Leon Hofmeister * @since Envoy v0.3-alpha */ -public class HandshakeSuccessfulEvent implements Event { +public class HandshakeSuccessfulEvent extends Event.Valueless { private static final long serialVersionUID = -157972384126278855L; } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 5aa18c5..045bf9c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -12,9 +12,9 @@ import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import envoy.client.Settings; import envoy.client.data.Chat; import envoy.client.data.LocalDb; +import envoy.client.data.Settings; import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.net.Client; diff --git a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java index f206c54..92f5204 100644 --- a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java @@ -6,7 +6,7 @@ import java.awt.Font; import javax.swing.*; -import envoy.client.Settings; +import envoy.client.data.Settings; import envoy.client.event.SendEvent; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index 6e7f9a1..d9e4750 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -8,8 +8,8 @@ import java.util.Arrays; import javax.swing.*; import javax.swing.border.EmptyBorder; +import envoy.client.data.Settings; import envoy.client.event.HandshakeSuccessfulEvent; -import envoy.client.Settings; import envoy.data.LoginCredentials; import envoy.event.EventBus; import envoy.event.HandshakeRejectionEvent; @@ -26,20 +26,20 @@ import envoy.event.HandshakeRejectionEvent; public class LoginDialog extends JDialog { private final JPanel contentPanel; - private JTextField textField; - private JPasswordField passwordField; - private JPasswordField repeatPasswordField; + private JTextField textField; + private JPasswordField passwordField; + private JPasswordField repeatPasswordField; private JLabel lblUserName; private JLabel lblPassword; private JLabel lblRepeatPassword; - private JLabel errorMessage; - + private JLabel errorMessage; + private GridBagConstraints gbc_lblRepeatPassword; private GridBagConstraints gbc_repeatPasswordField; - private GridBagConstraints gbc_errorMessage; + private GridBagConstraints gbc_errorMessage; - private JPanel buttonPane; + private JPanel buttonPane; private JTextPane registerText; private JCheckBox registerCheckBox; private PrimaryButton okButton; @@ -48,6 +48,7 @@ public class LoginDialog extends JDialog { private LoginCredentials credentials; private static final long serialVersionUID = 352021600833907468L; + /** * Displays a dialog enabling the user to enter their user name and password. * @@ -68,7 +69,7 @@ public class LoginDialog extends JDialog { contentPanel.setLayout(gbl_contentPanel); { lblUserName = new JLabel("Username:"); - GridBagConstraints gbc_lblUserName = new GridBagConstraints(); + GridBagConstraints gbc_lblUserName = new GridBagConstraints(); gbc_lblUserName.anchor = GridBagConstraints.EAST; gbc_lblUserName.insets = new Insets(0, 0, 5, 5); gbc_lblUserName.gridx = 0; @@ -88,7 +89,7 @@ public class LoginDialog extends JDialog { } { lblPassword = new JLabel("Password:"); - GridBagConstraints gbc_lblPassword = new GridBagConstraints(); + GridBagConstraints gbc_lblPassword = new GridBagConstraints(); gbc_lblPassword.anchor = GridBagConstraints.EAST; gbc_lblPassword.insets = new Insets(0, 0, 0, 5); gbc_lblPassword.gridx = 0; @@ -124,8 +125,8 @@ public class LoginDialog extends JDialog { contentPanel.remove(errorMessage); clearPasswordFields(); // TODO delete - only for testing purposes - System.out.println("Caught HandshakeRejectionEvent with reason" + ((HandshakeRejectionEvent) evt).get()); - errorMessage = new JLabel(((HandshakeRejectionEvent) evt).get()); + System.out.println("Caught HandshakeRejectionEvent with reason" + evt.get()); + errorMessage = new JLabel(evt.get()); gbc_errorMessage = new GridBagConstraints(); gbc_errorMessage.gridx = 2; gbc_errorMessage.gridy = 0; @@ -201,11 +202,11 @@ public class LoginDialog extends JDialog { setModal(true); setVisible(true); - EventBus.getInstance().register(HandshakeSuccessfulEvent.class, evt -> this.dispose()); + EventBus.getInstance().register(HandshakeSuccessfulEvent.class, evt -> dispose()); } /** - * Resets the text stored by this + * Resets the text stored in the passwort fields. * * @since Envoy v0.3-alpha */ diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 65ee63a..a069721 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -5,7 +5,7 @@ import java.text.SimpleDateFormat; import javax.swing.*; -import envoy.client.Settings; +import envoy.client.data.Settings; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; import envoy.data.Message; diff --git a/src/main/java/envoy/client/ui/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/PrimaryScrollBar.java index a7cb8fc..8e8131c 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/PrimaryScrollBar.java @@ -12,7 +12,7 @@ import javax.swing.JComponent; import javax.swing.JScrollBar; import javax.swing.plaf.basic.BasicScrollBarUI; -import envoy.client.Settings; +import envoy.client.data.Settings; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 2882a05..3f58e2e 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -5,8 +5,8 @@ import java.awt.Graphics; import javax.swing.JButton; -import envoy.client.Settings; -import envoy.client.SettingsItem; +import envoy.client.data.Settings; +import envoy.client.data.SettingsItem; /** * This component can be used to toggle between two options. This will change diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 24f6a9f..db55c53 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -11,7 +11,6 @@ import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; -import envoy.client.Settings; import envoy.client.data.*; import envoy.client.net.Client; import envoy.client.net.WriteProxy; @@ -79,7 +78,7 @@ public class Startup { LoginCredentials credentials = config.hasLoginCredentials() ? config.getLoginCredentials() : new LoginDialog().getCredentials(); if (credentials == null) { - logger.info("The login process has been aborted by the user. Exiting..."); + logger.info("The login process has been cancelled. Exiting..."); System.exit(0); } diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index 8c63ad7..c43eeb6 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -7,7 +7,7 @@ import javax.swing.JLabel; import javax.swing.JList; import javax.swing.ListCellRenderer; -import envoy.client.Settings; +import envoy.client.data.Settings; import envoy.data.User; import envoy.data.User.UserStatus; diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index adafc2e..a1b5966 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -10,8 +10,8 @@ import java.util.logging.Logger; import javax.swing.JComponent; import javax.swing.JTextPane; -import envoy.client.Settings; -import envoy.client.SettingsItem; +import envoy.client.data.Settings; +import envoy.client.data.SettingsItem; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; diff --git a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java index 3e259e4..02dd42a 100644 --- a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java +++ b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java @@ -7,7 +7,7 @@ import javax.swing.JDialog; import javax.swing.JPanel; import javax.swing.JTextPane; -import envoy.client.Settings; +import envoy.client.data.Settings; import envoy.client.ui.PrimaryButton; import envoy.client.ui.PrimaryTextArea; import envoy.client.ui.Theme; diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index af68e8e..df2fa2c 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -9,7 +9,7 @@ import java.util.logging.Logger; import javax.swing.*; -import envoy.client.Settings; +import envoy.client.data.Settings; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.PrimaryButton; import envoy.client.ui.Theme; diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 8df3491..ed4be4f 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -9,7 +9,7 @@ import java.util.logging.Logger; import javax.swing.*; -import envoy.client.Settings; +import envoy.client.data.Settings; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.Color; import envoy.client.ui.Theme; From 9498bf216d98046fe7822b124813376d4e098fb9 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 12 Feb 2020 07:53:24 +0100 Subject: [PATCH 243/474] Split Client#onlineInit method up into performHandshake and initReceiver --- pom.xml | 2 +- src/main/java/envoy/client/net/Client.java | 46 ++++++++++++++++++---- src/main/java/envoy/client/ui/Startup.java | 5 ++- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index ec25577..6106227 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - develop-SNAPSHOT + f~advanced_login-SNAPSHOT diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 9f84364..b404807 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -42,6 +42,7 @@ public class Client implements Closeable { // Asynchronously initialized during handshake private volatile User sender; private volatile Contacts contacts; + private volatile boolean rejected; // Configuration and logging private static final Config config = Config.getInstance(); @@ -54,16 +55,19 @@ public class Client implements Closeable { * an exception is thrown. * * @param credentials the login credentials of the user - * @param localDb the local database used to persist the current - * {@link IdGenerator} * @param receivedMessageCache a message cache containing all unread messages * from the server that can be relayed after * initialization - * @throws Exception if the online mode could not be entered or the request - * failed for some other reason - * @since Envoy v0.2-alpha + * @throws TimeLimitExceededException if the server could not be reached + * @throws IOException if the login credentials could not be + * written + * @throws InterruptedException if the current thread is interrupted while + * waiting for the handshake response */ - public void onlineInit(LoginCredentials credentials, LocalDb localDb, Cache receivedMessageCache) throws Exception { + public void performHandshake(LoginCredentials credentials, Cache receivedMessageCache) + throws TimeLimitExceededException, IOException, InterruptedException { + if (online) throw new IllegalStateException("Handshake has already been performed successfully"); + // Establish TCP connection logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); socket = new Socket(config.getServer(), config.getPort()); @@ -76,7 +80,9 @@ public class Client implements Closeable { receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); receiver.registerProcessor(Contacts.class, contacts -> { logger.info("Acquired contacts object " + contacts); this.contacts = contacts; }); receiver.registerProcessor(Message.class, receivedMessageCache); - receiver.registerProcessor(HandshakeRejectionEvent.class, EventBus.getInstance()::dispatch); + receiver.registerProcessor(HandshakeRejectionEvent.class, evt -> { rejected = true; EventBus.getInstance().dispatch(evt); }); + + rejected = false; // Start receiver new Thread(receiver).start(); @@ -88,6 +94,15 @@ public class Client implements Closeable { // Wait for a maximum of five seconds to acquire the sender object long start = System.currentTimeMillis(); while (sender == null || contacts == null) { + + // Quit immediately after handshake rejection + // This method can then be called again + if (rejected) { + socket.close(); + receiver.removeAllProcessors(); + return; + } + if (System.currentTimeMillis() - start > 5000) throw new TimeLimitExceededException("Did not log in after 5 seconds"); Thread.sleep(500); } @@ -97,8 +112,23 @@ public class Client implements Closeable { // Remove user creation processor receiver.removeAllProcessors(); + } - // Register processors for message and status handling + /** + * Initializes the {@link Receiver} used to process data sent from the server to + * this client. + * + * @param localDb the local database used to persist the current + * {@link IdGenerator} + * @param receivedMessageCache a message cache containing all unread messages + * from the server that can be relayed after + * initialization + * @throws IOException if no {@link IdGenerator} is present and none could be + * requested from the server + * @since Envoy v0.2-alpha + */ + public void initReceiver(LocalDb localDb, Cache receivedMessageCache) throws IOException { + checkOnline(); // Process incoming messages final ReceivedMessageProcessor receivedMessageProcessor = new ReceivedMessageProcessor(); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index db55c53..f31cfa3 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -62,7 +62,7 @@ public class Startup { if (args.length > 0) config.load(args); // Check if all mandatory configuration values have been initialized - if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined"); + if (!config.isInitialized()) throw new EnvoyException("Configuration is not fully initialized"); } catch (Exception e) { JOptionPane .showMessageDialog(null, "Error loading configuration values:\n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE); @@ -109,7 +109,8 @@ public class Startup { try { // Try entering online mode first localDb.loadIdGenerator(); - client.onlineInit(credentials, localDb, cache); + client.performHandshake(credentials, cache); + client.initReceiver(localDb, cache); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); e1.printStackTrace(); From b3101e2418dd92d3c6b1314e6401354285d6c41a Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 12 Feb 2020 17:31:20 +0100 Subject: [PATCH 244/474] Performing handshake and online init in LoginDialog --- src/main/java/envoy/client/net/Receiver.java | 2 +- .../java/envoy/client/ui/LoginDialog.java | 337 ++++++++++-------- src/main/java/envoy/client/ui/Startup.java | 46 +-- 3 files changed, 205 insertions(+), 180 deletions(-) diff --git a/src/main/java/envoy/client/net/Receiver.java b/src/main/java/envoy/client/net/Receiver.java index 25e7153..d8a0d45 100644 --- a/src/main/java/envoy/client/net/Receiver.java +++ b/src/main/java/envoy/client/net/Receiver.java @@ -51,7 +51,7 @@ public class Receiver implements Runnable { try (ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(objBytes))) { Object obj = oin.readObject(); - logger.finest("Received object " + obj); + logger.info("Received object " + obj); // Get appropriate processor @SuppressWarnings("rawtypes") diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index d9e4750..bdac73a 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -2,17 +2,25 @@ package envoy.client.ui; import java.awt.*; import java.awt.event.ItemEvent; +import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.logging.Logger; +import javax.naming.TimeLimitExceededException; import javax.swing.*; import javax.swing.border.EmptyBorder; -import envoy.client.data.Settings; +import envoy.client.data.*; import envoy.client.event.HandshakeSuccessfulEvent; +import envoy.client.net.Client; +import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; +import envoy.data.Message; +import envoy.data.User; import envoy.event.EventBus; import envoy.event.HandshakeRejectionEvent; +import envoy.exception.EnvoyException; /** * Project: envoy-client
@@ -25,7 +33,7 @@ import envoy.event.HandshakeRejectionEvent; */ public class LoginDialog extends JDialog { - private final JPanel contentPanel; + private JPanel contentPanel; private JTextField textField; private JPasswordField passwordField; private JPasswordField repeatPasswordField; @@ -47,14 +55,111 @@ public class LoginDialog extends JDialog { private LoginCredentials credentials; - private static final long serialVersionUID = 352021600833907468L; + private final Client client; + private final LocalDb localDb; + private final Cache receivedMessageCache; + + private static final Config config = Config.getInstance(); + private static final Logger logger = EnvoyLog.getLogger(LoginDialog.class.getSimpleName()); + private static final long serialVersionUID = 352021600833907468L; /** * Displays a dialog enabling the user to enter their user name and password. * + * @param client the client used to perform the handshake + * @param localDb the local database in which data is persisted + * @param receivedMessageCache the cache that stored messages received during + * the handshake * @since Envoy v0.3-alpha */ - public LoginDialog() { + public LoginDialog(Client client, LocalDb localDb, Cache receivedMessageCache) { + this.client = client; + this.localDb = localDb; + this.receivedMessageCache = receivedMessageCache; + + // Prepare handshake + localDb.loadIdGenerator(); + + initUi(); + + okButton.addActionListener((evt) -> { + try { + if (registerCheckBox.isSelected()) { + // Check password equality + if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) + credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), true); + else { + JOptionPane.showMessageDialog(this, "The repeated password is not the origional password!"); + clearPasswordFields(); + } + } else credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); + performHandshake(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + }); + + // Listen to handshake rejections + EventBus.getInstance().register(HandshakeRejectionEvent.class, evt -> { + for (Component c : contentPanel.getComponents()) + if (c == errorMessage) contentPanel.remove(errorMessage); + clearPasswordFields(); + errorMessage = new JLabel(evt.get()); + gbc_errorMessage = new GridBagConstraints(); + gbc_errorMessage.gridx = 2; + gbc_errorMessage.gridy = 0; + gbc_errorMessage.fill = GridBagConstraints.HORIZONTAL; + gbc_errorMessage.insets = new Insets(5, 5, 5, 5); + contentPanel.add(errorMessage, gbc_errorMessage); + contentPanel.revalidate(); + contentPanel.repaint(); + }); + + // Exit the application when the dialog is cancelled + cancelButton.addActionListener(evt -> { logger.info("The login process has been cancelled. Exiting..."); System.exit(0); }); + + // Log in directly if configured + if (config.hasLoginCredentials()) { + credentials = config.getLoginCredentials(); + performHandshake(); + return; + } + + setVisible(true); + } + + private void performHandshake() { + try { + client.performHandshake(credentials, receivedMessageCache); + if (client.isOnline()) { + client.initReceiver(localDb, receivedMessageCache); + dispose(); + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } catch (TimeLimitExceededException e) { + logger.warning("Could not connect to server. Trying offline mode..."); + e.printStackTrace(); + try { + // Try entering offline mode + localDb.loadUsers(); + User clientUser = localDb.getUsers().get(credentials.getIdentifier()); + if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); + client.setSender(clientUser); + JOptionPane.showMessageDialog(null, + "A connection to the server could not be established. Starting in offline mode.\n" + e, + "Connection error", + JOptionPane.WARNING_MESSAGE); + dispose(); + } catch (Exception e1) { + JOptionPane.showMessageDialog(null, e1, "Client error", JOptionPane.ERROR_MESSAGE); + System.exit(1); + return; + } + } + } + + private void initUi() { setSize(338, 123); setLocationRelativeTo(null); getContentPane().setLayout(new BorderLayout()); @@ -67,150 +172,109 @@ public class LoginDialog extends JDialog { gbl_contentPanel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE }; gbl_contentPanel.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE }; contentPanel.setLayout(gbl_contentPanel); - { - lblUserName = new JLabel("Username:"); - GridBagConstraints gbc_lblUserName = new GridBagConstraints(); - gbc_lblUserName.anchor = GridBagConstraints.EAST; - gbc_lblUserName.insets = new Insets(0, 0, 5, 5); - gbc_lblUserName.gridx = 0; - gbc_lblUserName.gridy = 0; - contentPanel.add(lblUserName, gbc_lblUserName); - } - { - textField = new JTextField(); - textField.setBorder(null); - GridBagConstraints gbc_textField = new GridBagConstraints(); - gbc_textField.insets = new Insets(0, 0, 5, 0); - gbc_textField.fill = GridBagConstraints.HORIZONTAL; - gbc_textField.gridx = 1; - gbc_textField.gridy = 0; - contentPanel.add(textField, gbc_textField); - textField.setColumns(10); - } - { - lblPassword = new JLabel("Password:"); - GridBagConstraints gbc_lblPassword = new GridBagConstraints(); - gbc_lblPassword.anchor = GridBagConstraints.EAST; - gbc_lblPassword.insets = new Insets(0, 0, 0, 5); - gbc_lblPassword.gridx = 0; - gbc_lblPassword.gridy = 1; - contentPanel.add(lblPassword, gbc_lblPassword); - } - { - passwordField = new JPasswordField(); - passwordField.setBorder(null); - GridBagConstraints gbc_passwordField = new GridBagConstraints(); - gbc_passwordField.fill = GridBagConstraints.HORIZONTAL; - gbc_passwordField.gridx = 1; - gbc_passwordField.gridy = 1; - contentPanel.add(passwordField, gbc_passwordField); - } - { - lblRepeatPassword = new JLabel("Repeat Password:"); - gbc_lblRepeatPassword = new GridBagConstraints(); - gbc_lblRepeatPassword.anchor = GridBagConstraints.EAST; - gbc_lblRepeatPassword.insets = new Insets(0, 0, 0, 5); - gbc_lblRepeatPassword.gridx = 0; - gbc_lblRepeatPassword.gridy = 2; - } - { - repeatPasswordField = new JPasswordField(); - gbc_repeatPasswordField = new GridBagConstraints(); - gbc_repeatPasswordField.fill = GridBagConstraints.HORIZONTAL; - gbc_repeatPasswordField.gridx = 1; - gbc_repeatPasswordField.gridy = 2; - } - { - EventBus.getInstance().register(HandshakeRejectionEvent.class, evt -> { - contentPanel.remove(errorMessage); - clearPasswordFields(); - // TODO delete - only for testing purposes - System.out.println("Caught HandshakeRejectionEvent with reason" + evt.get()); - errorMessage = new JLabel(evt.get()); - gbc_errorMessage = new GridBagConstraints(); - gbc_errorMessage.gridx = 2; - gbc_errorMessage.gridy = 0; - gbc_errorMessage.fill = GridBagConstraints.HORIZONTAL; - gbc_errorMessage.insets = new Insets(5, 5, 5, 5); - contentPanel.add(errorMessage, gbc_errorMessage); - }); - } - { - buttonPane = new JPanel(); - registerText = new JTextPane(); - registerText.setEditable(false); - registerText.setText("Register?"); - registerText.setFont(new Font("Arial", Font.BOLD, 12)); - registerText.setAlignmentX(LEFT_ALIGNMENT); - buttonPane.add(registerText); + lblUserName = new JLabel("Username:"); + GridBagConstraints gbc_lblUserName = new GridBagConstraints(); + gbc_lblUserName.anchor = GridBagConstraints.EAST; + gbc_lblUserName.insets = new Insets(0, 0, 5, 5); + gbc_lblUserName.gridx = 0; + gbc_lblUserName.gridy = 0; + contentPanel.add(lblUserName, gbc_lblUserName); - registerCheckBox = new JCheckBox(); - registerCheckBox.setAlignmentX(LEFT_ALIGNMENT); - registerCheckBox.addItemListener(e -> { - switch (e.getStateChange()) { - case ItemEvent.SELECTED: - contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword); - contentPanel.add(repeatPasswordField, gbc_repeatPasswordField); - setSize(338, 148); - break; + textField = new JTextField(); + textField.setBorder(null); + GridBagConstraints gbc_textField = new GridBagConstraints(); + gbc_textField.insets = new Insets(0, 0, 5, 0); + gbc_textField.fill = GridBagConstraints.HORIZONTAL; + gbc_textField.gridx = 1; + gbc_textField.gridy = 0; + contentPanel.add(textField, gbc_textField); + textField.setColumns(10); - case ItemEvent.DESELECTED: - if (repeatPasswordField.getParent() == contentPanel) { - contentPanel.remove(lblRepeatPassword); - contentPanel.remove(repeatPasswordField); - setSize(338, 123); - } - break; - } - contentPanel.revalidate(); - contentPanel.repaint(); - }); - buttonPane.add(registerCheckBox); + lblPassword = new JLabel("Password:"); + GridBagConstraints gbc_lblPassword = new GridBagConstraints(); + gbc_lblPassword.anchor = GridBagConstraints.EAST; + gbc_lblPassword.insets = new Insets(0, 0, 0, 5); + gbc_lblPassword.gridx = 0; + gbc_lblPassword.gridy = 1; + contentPanel.add(lblPassword, gbc_lblPassword); - buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); - getContentPane().add(buttonPane, BorderLayout.SOUTH); - { - okButton = new PrimaryButton("OK"); - okButton.addActionListener((evt) -> { - try { - if (registerCheckBox.isSelected()) { - // password checking - if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) - credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), true); - else { - JOptionPane.showMessageDialog(this, "The repeated password is not the origional password!"); - clearPasswordFields(); - } - } else credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); + passwordField = new JPasswordField(); + passwordField.setBorder(null); + GridBagConstraints gbc_passwordField = new GridBagConstraints(); + gbc_passwordField.fill = GridBagConstraints.HORIZONTAL; + gbc_passwordField.gridx = 1; + gbc_passwordField.gridy = 1; + contentPanel.add(passwordField, gbc_passwordField); + + lblRepeatPassword = new JLabel("Repeat Password:"); + gbc_lblRepeatPassword = new GridBagConstraints(); + gbc_lblRepeatPassword.anchor = GridBagConstraints.EAST; + gbc_lblRepeatPassword.insets = new Insets(0, 0, 0, 5); + gbc_lblRepeatPassword.gridx = 0; + gbc_lblRepeatPassword.gridy = 2; + + repeatPasswordField = new JPasswordField(); + gbc_repeatPasswordField = new GridBagConstraints(); + gbc_repeatPasswordField.fill = GridBagConstraints.HORIZONTAL; + gbc_repeatPasswordField.gridx = 1; + gbc_repeatPasswordField.gridy = 2; + + buttonPane = new JPanel(); + + registerText = new JTextPane(); + registerText.setEditable(false); + registerText.setText("Register?"); + registerText.setFont(new Font("Arial", Font.BOLD, 12)); + registerText.setAlignmentX(LEFT_ALIGNMENT); + buttonPane.add(registerText); + + registerCheckBox = new JCheckBox(); + registerCheckBox.setAlignmentX(LEFT_ALIGNMENT); + registerCheckBox.addItemListener(e -> { + switch (e.getStateChange()) { + case ItemEvent.SELECTED: + contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword); + contentPanel.add(repeatPasswordField, gbc_repeatPasswordField); + setSize(338, 148); + break; + + case ItemEvent.DESELECTED: + if (repeatPasswordField.getParent() == contentPanel) { + contentPanel.remove(lblRepeatPassword); + contentPanel.remove(repeatPasswordField); + setSize(338, 123); } - }); - okButton.setActionCommand("OK"); - buttonPane.add(okButton); - getRootPane().setDefaultButton(okButton); + break; } - { - cancelButton = new PrimaryButton("Cancel"); - cancelButton.addActionListener((evt) -> dispose()); - cancelButton.setActionCommand("Cancel"); - buttonPane.add(cancelButton); - } - } + contentPanel.revalidate(); + contentPanel.repaint(); + }); + buttonPane.add(registerCheckBox); + + buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + okButton = new PrimaryButton("OK"); + okButton.setActionCommand("OK"); + buttonPane.add(okButton); + getRootPane().setDefaultButton(okButton); + + cancelButton = new PrimaryButton("Cancel"); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton); setTheme(); - setModal(true); - setVisible(true); + setModalityType(Dialog.DEFAULT_MODALITY_TYPE); + EventBus.getInstance().register(HandshakeSuccessfulEvent.class, evt -> dispose()); } /** - * Resets the text stored in the passwort fields. + * Resets the text stored in the password fields. * * @since Envoy v0.3-alpha */ - public void clearPasswordFields() { + private void clearPasswordFields() { passwordField.setText(null); repeatPasswordField.setText(null); } @@ -258,11 +322,4 @@ public class LoginDialog extends JDialog { cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor()); } - - /** - * @return the {@link LoginCredentials} entered by the user, or {@code null} if - * the dialog has been cancelled - * @since Envoy v0.3-alpha - */ - public LoginCredentials getCredentials() { return credentials; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index f31cfa3..a684326 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -15,9 +15,7 @@ import envoy.client.data.*; import envoy.client.net.Client; import envoy.client.net.WriteProxy; import envoy.client.util.EnvoyLog; -import envoy.data.LoginCredentials; import envoy.data.Message; -import envoy.data.User; import envoy.exception.EnvoyException; /** @@ -74,14 +72,6 @@ public class Startup { EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); - // Acquire login credentials - LoginCredentials credentials = config.hasLoginCredentials() ? config.getLoginCredentials() : new LoginDialog().getCredentials(); - - if (credentials == null) { - logger.info("The login process has been cancelled. Exiting..."); - System.exit(0); - } - // Initialize the local database LocalDb localDb; if (config.isIgnoreLocalDB()) { @@ -95,45 +85,23 @@ public class Startup { } catch (IOException e3) { logger.log(Level.SEVERE, "Could not initialize local database", e3); JOptionPane - .showMessageDialog(null, "Could not initialize local database!\n" + e3.toString(), "Local database error", JOptionPane.ERROR_MESSAGE); + .showMessageDialog(null, "Could not initialize local database!\n" + e3, "Local database error", JOptionPane.ERROR_MESSAGE); System.exit(1); return; } - SwingUtilities.invokeLater(() -> chatWindow.setVisible(true)); - - // Acquire the client user (with ID) either from the server or from the local - // database, which triggers offline mode + // Initialize client and unread message cache Client client = new Client(); Cache cache = new Cache<>(); - try { - // Try entering online mode first - localDb.loadIdGenerator(); - client.performHandshake(credentials, cache); - client.initReceiver(localDb, cache); - } catch (Exception e1) { - logger.warning("Could not connect to server. Trying offline mode..."); - e1.printStackTrace(); - try { - // Try entering offline mode - localDb.loadUsers(); - User clientUser = localDb.getUsers().get(credentials.getIdentifier()); - if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); - client.setSender(clientUser); - JOptionPane.showMessageDialog(null, - "A connection to the server could not be established. Starting in offline mode.\n" + e1, - "Connection error", - JOptionPane.WARNING_MESSAGE); - } catch (Exception e2) { - JOptionPane.showMessageDialog(null, e2.toString(), "Client error", JOptionPane.ERROR_MESSAGE); - System.exit(1); - return; - } - } + + // Try to connect to the server + new LoginDialog(client, localDb, cache); + SwingUtilities.invokeLater(() -> chatWindow.setVisible(true)); // Set client user in local database localDb.setUser(client.getSender()); + // Initialize chats in local database try { localDb.initializeUserStorage(); From 84fd2229565437d3a7d1184cf024e30e0b71f501 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 12 Feb 2020 22:22:29 +0100 Subject: [PATCH 245/474] Fixed entering offline mode --- src/main/java/envoy/client/ui/LoginDialog.java | 7 ++----- src/main/java/envoy/client/ui/Startup.java | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index bdac73a..40991c6 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -101,8 +101,7 @@ public class LoginDialog extends JDialog { // Listen to handshake rejections EventBus.getInstance().register(HandshakeRejectionEvent.class, evt -> { - for (Component c : contentPanel.getComponents()) - if (c == errorMessage) contentPanel.remove(errorMessage); + if (errorMessage != null) contentPanel.remove(errorMessage); clearPasswordFields(); errorMessage = new JLabel(evt.get()); gbc_errorMessage = new GridBagConstraints(); @@ -135,9 +134,7 @@ public class LoginDialog extends JDialog { client.initReceiver(localDb, receivedMessageCache); dispose(); } - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - } catch (TimeLimitExceededException e) { + } catch (IOException | InterruptedException | TimeLimitExceededException e) { logger.warning("Could not connect to server. Trying offline mode..."); e.printStackTrace(); try { diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index a684326..5427fe1 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -101,7 +101,6 @@ public class Startup { // Set client user in local database localDb.setUser(client.getSender()); - // Initialize chats in local database try { localDb.initializeUserStorage(); From 6e211a01a1297934dc7268db4b924df5b9d39d88 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 13 Feb 2020 10:11:25 +0100 Subject: [PATCH 246/474] Fixed error message layout in LoginDialog Updated envoy-common dependency to v0.2-alpha in pom.xml --- pom.xml | 2 +- .../java/envoy/client/ui/LoginDialog.java | 31 ++++++++++--------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index 6106227..e670832 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - f~advanced_login-SNAPSHOT + v0.2-alpha diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index 40991c6..09fd551 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -100,19 +100,9 @@ public class LoginDialog extends JDialog { }); // Listen to handshake rejections - EventBus.getInstance().register(HandshakeRejectionEvent.class, evt -> { - if (errorMessage != null) contentPanel.remove(errorMessage); - clearPasswordFields(); - errorMessage = new JLabel(evt.get()); - gbc_errorMessage = new GridBagConstraints(); - gbc_errorMessage.gridx = 2; - gbc_errorMessage.gridy = 0; - gbc_errorMessage.fill = GridBagConstraints.HORIZONTAL; - gbc_errorMessage.insets = new Insets(5, 5, 5, 5); - contentPanel.add(errorMessage, gbc_errorMessage); - contentPanel.revalidate(); - contentPanel.repaint(); - }); + EventBus.getInstance() + .register(HandshakeRejectionEvent.class, + evt -> { clearPasswordFields(); errorMessage.setVisible(true); errorMessage.setText(evt.get()); }); // Exit the application when the dialog is cancelled cancelButton.addActionListener(evt -> { logger.info("The login process has been cancelled. Exiting..."); System.exit(0); }); @@ -159,6 +149,7 @@ public class LoginDialog extends JDialog { private void initUi() { setSize(338, 123); setLocationRelativeTo(null); + setResizable(false); getContentPane().setLayout(new BorderLayout()); contentPanel = new JPanel(); contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); @@ -217,6 +208,16 @@ public class LoginDialog extends JDialog { gbc_repeatPasswordField.gridx = 1; gbc_repeatPasswordField.gridy = 2; + errorMessage = new JLabel(); + gbc_errorMessage = new GridBagConstraints(); + gbc_errorMessage.gridx = 1; + gbc_errorMessage.gridy = 3; + gbc_errorMessage.fill = GridBagConstraints.HORIZONTAL; + gbc_errorMessage.insets = new Insets(5, 5, 5, 5); + errorMessage.setForeground(Color.RED); + errorMessage.setVisible(false); + contentPanel.add(errorMessage, gbc_errorMessage); + buttonPane = new JPanel(); registerText = new JTextPane(); @@ -233,14 +234,14 @@ public class LoginDialog extends JDialog { case ItemEvent.SELECTED: contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword); contentPanel.add(repeatPasswordField, gbc_repeatPasswordField); - setSize(338, 148); + setSize(338, 173); break; case ItemEvent.DESELECTED: if (repeatPasswordField.getParent() == contentPanel) { contentPanel.remove(lblRepeatPassword); contentPanel.remove(repeatPasswordField); - setSize(338, 123); + setSize(338, 148); } break; } From 7129e82038dcd5b6dac84b6719dfcf77798bda20 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 16 Feb 2020 21:53:10 +0100 Subject: [PATCH 247/474] Appended timestamp to log file names --- src/main/java/envoy/client/util/EnvoyLog.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index ae6c6e5..a6391c6 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -2,6 +2,8 @@ package envoy.client.util; import java.io.File; import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.logging.*; import envoy.client.data.Config; @@ -25,7 +27,8 @@ public class EnvoyLog { LogManager.getLogManager().reset(); // Configure log file - File logFile = new File(Config.getInstance().getHomeDirectory(), "log/envoy_user.log"); + File logFile = new File(Config.getInstance().getHomeDirectory(), + "log/envoy_user_" + new SimpleDateFormat("yyyy-MM-dd--hh-mm-mm").format(new Date()) + ".log"); logFile.getParentFile().mkdirs(); // Configure formatting From a7e9c70cfcb8a6ea939fc5de5b860b94ea32a4a3 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 18 Feb 2020 07:16:35 +0100 Subject: [PATCH 248/474] Fixed logger level configuration, using logger hierarchy Loggers are now created with a class object --- src/main/java/envoy/client/data/Cache.java | 2 +- src/main/java/envoy/client/net/Client.java | 2 +- .../MessageStatusChangeEventProcessor.java | 2 +- .../client/net/ReceivedMessageProcessor.java | 4 +-- src/main/java/envoy/client/net/Receiver.java | 4 +-- .../java/envoy/client/net/WriteProxy.java | 2 +- src/main/java/envoy/client/ui/ChatWindow.java | 2 +- .../java/envoy/client/ui/LoginDialog.java | 2 +- src/main/java/envoy/client/ui/Startup.java | 2 +- .../ui/settings/GeneralSettingsPanel.java | 6 ++--- .../client/ui/settings/SettingsScreen.java | 2 +- .../ui/settings/ThemeCustomizationPanel.java | 2 +- src/main/java/envoy/client/util/EnvoyLog.java | 27 +++++++++++-------- 13 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/main/java/envoy/client/data/Cache.java b/src/main/java/envoy/client/data/Cache.java index 80ef26f..078c377 100644 --- a/src/main/java/envoy/client/data/Cache.java +++ b/src/main/java/envoy/client/data/Cache.java @@ -24,7 +24,7 @@ public class Cache implements Consumer, Serializable { private final Queue elements = new LinkedList<>(); private transient Consumer processor; - private static final Logger logger = EnvoyLog.getLogger(Cache.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(Cache.class); private static final long serialVersionUID = 7343544675545545076L; /** diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index b404807..5cd1b15 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -46,7 +46,7 @@ public class Client implements Closeable { // Configuration and logging private static final Config config = Config.getInstance(); - private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(Client.class); /** * Enters the online mode by acquiring a user ID from the server. As a diff --git a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java index b81561c..774b06b 100644 --- a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java +++ b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java @@ -18,7 +18,7 @@ import envoy.event.MessageStatusChangeEvent; */ public class MessageStatusChangeEventProcessor implements Consumer { - private static final Logger logger = EnvoyLog.getLogger(MessageStatusChangeEventProcessor.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(MessageStatusChangeEventProcessor.class); /** * Dispatches a {@link MessageStatusChangeEvent} if the status is diff --git a/src/main/java/envoy/client/net/ReceivedMessageProcessor.java b/src/main/java/envoy/client/net/ReceivedMessageProcessor.java index 5916950..5196402 100644 --- a/src/main/java/envoy/client/net/ReceivedMessageProcessor.java +++ b/src/main/java/envoy/client/net/ReceivedMessageProcessor.java @@ -13,13 +13,13 @@ import envoy.event.EventBus; * Project: envoy-client
* File: ReceivedMessageProcessor.java
* Created: 31.12.2019
- * + * * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ public class ReceivedMessageProcessor implements Consumer { - private static final Logger logger = EnvoyLog.getLogger(ReceivedMessageProcessor.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(ReceivedMessageProcessor.class); @Override public void accept(Message message) { diff --git a/src/main/java/envoy/client/net/Receiver.java b/src/main/java/envoy/client/net/Receiver.java index d8a0d45..1746f73 100644 --- a/src/main/java/envoy/client/net/Receiver.java +++ b/src/main/java/envoy/client/net/Receiver.java @@ -26,7 +26,7 @@ public class Receiver implements Runnable { private final InputStream in; private final Map, Consumer> processors = new HashMap<>(); - private static final Logger logger = EnvoyLog.getLogger(Receiver.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(Receiver.class); /** * Creates an instance of {@link Receiver}. @@ -51,7 +51,7 @@ public class Receiver implements Runnable { try (ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(objBytes))) { Object obj = oin.readObject(); - logger.info("Received object " + obj); + logger.fine("Received object " + obj); // Get appropriate processor @SuppressWarnings("rawtypes") diff --git a/src/main/java/envoy/client/net/WriteProxy.java b/src/main/java/envoy/client/net/WriteProxy.java index 93e67d8..e06ae88 100644 --- a/src/main/java/envoy/client/net/WriteProxy.java +++ b/src/main/java/envoy/client/net/WriteProxy.java @@ -26,7 +26,7 @@ public class WriteProxy { private final Client client; private final LocalDb localDb; - private static final Logger logger = EnvoyLog.getLogger(WriteProxy.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(WriteProxy.class); /** * Initializes a write proxy using a client and a local database. The diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 045bf9c..3602283 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -72,7 +72,7 @@ public class ChatWindow extends JFrame { private final ComponentListModel contactsModel = new ComponentListModel<>(); private final ComponentList contactList = new ComponentList<>(contactRenderer); - private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class); // GUI component spacing private final static int space = 4; diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index 09fd551..7b93bdf 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -60,7 +60,7 @@ public class LoginDialog extends JDialog { private final Cache receivedMessageCache; private static final Config config = Config.getInstance(); - private static final Logger logger = EnvoyLog.getLogger(LoginDialog.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(LoginDialog.class); private static final long serialVersionUID = 352021600833907468L; /** diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 5427fe1..a6c1aaa 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -34,7 +34,7 @@ public class Startup { private static ChatWindow chatWindow; - private static final Logger logger = EnvoyLog.getLogger(Startup.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(Startup.class); /** * Loads the application by first loading the configuration, then acquiring a diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index a1b5966..fc91740 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -21,7 +21,7 @@ import envoy.client.util.EnvoyLog; * Project: envoy-client
* File: GeneralSettingsPanel.java
* Created: 21 Dec 2019
- * + * * @author Maximilian Käfer * @since Envoy v0.3-alpha */ @@ -30,13 +30,13 @@ public class GeneralSettingsPanel extends SettingsPanel { private Theme theme; private static final String[] items = { "onCloseMode", "enterToSend" }; - private static final Logger logger = EnvoyLog.getLogger(GeneralSettingsPanel.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(GeneralSettingsPanel.class); private static final long serialVersionUID = -7470848775130754239L; /** * This is the constructor for the General class. Here the user can set general * settings for the client. - * + * * @param parent the {@link SettingsScreen} as a part of which this * {@link SettingsPanel} is displayed * @since Envoy v0.3-alpha diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index df2fa2c..a84085b 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -47,7 +47,7 @@ public class SettingsScreen extends JDialog { private SettingsPanel settingsPanel; - private static final Logger logger = EnvoyLog.getLogger(SettingsScreen.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(SettingsScreen.class); /** * Initializes the settings screen. diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index ed4be4f..09a05e2 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -40,7 +40,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { private final Insets insets = new Insets(5, 5, 5, 5); - private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class.getSimpleName()); + private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class); private static final long serialVersionUID = -8697897390666456624L; /** diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index a6391c6..451810f 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -19,6 +19,7 @@ import envoy.client.data.Config; */ public class EnvoyLog { + private static Logger root; private static FileHandler fileHandler; private static StreamHandler consoleHandler; @@ -26,6 +27,9 @@ public class EnvoyLog { // Remove default console handler LogManager.getLogManager().reset(); + // Get root logger + root = Logger.getLogger("envoy"); + // Configure log file File logFile = new File(Config.getInstance().getHomeDirectory(), "log/envoy_user_" + new SimpleDateFormat("yyyy-MM-dd--hh-mm-mm").format(new Date()) + ".log"); @@ -39,12 +43,16 @@ public class EnvoyLog { fileHandler = new FileHandler(logFile.getAbsolutePath()); fileHandler.setLevel(Config.getInstance().getFileLevelBarrier()); fileHandler.setFormatter(formatter); + root.addHandler(fileHandler); } catch (SecurityException | IOException e) { e.printStackTrace(); } consoleHandler = new StreamHandler(System.out, formatter); consoleHandler.setLevel(Config.getInstance().getConsoleLevelBarrier()); consoleHandler.setFormatter(formatter); + root.addHandler(consoleHandler); + + root.setLevel(Level.ALL); } private EnvoyLog() {} @@ -52,19 +60,13 @@ public class EnvoyLog { /** * Creates a {@link Logger} with a specified name * - * @param name the name of the {@link Logger} to create + * @param logClass the class in which the logger is used * @return the created {@link Logger} * @since Envoy v0.2-alpha */ - public static Logger getLogger(String name) { - // Get a logger with the specified name - Logger logger = Logger.getLogger(name); - - // Add handlers - if (fileHandler != null) logger.addHandler(fileHandler); - if (consoleHandler != null) logger.addHandler(consoleHandler); - - return logger; + public static Logger getLogger(Class logClass) { + // Get a logger with the specified class name + return Logger.getLogger(logClass.getCanonicalName()); } /** @@ -74,7 +76,10 @@ public class EnvoyLog { * from 0 - 1000 or with the according name of the level * @since Envoy v0.2-alpha */ - public static void setFileLevelBarrier(Level fileLevelBarrier) { if (fileHandler != null) fileHandler.setLevel(fileLevelBarrier); } + public static void setFileLevelBarrier(Level fileLevelBarrier) { + if (fileHandler != null) fileHandler.setLevel(fileLevelBarrier); + + } /** * @param consoleLevelBarrier the severity below which logRecords will not be From 6dd1b40130fec87e4e3cd3eed5b915e3b792ca95 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 18 Feb 2020 08:14:04 +0100 Subject: [PATCH 249/474] Adder EnvoyLog#attach(String) method to log specific packages --- src/main/java/envoy/client/ui/Startup.java | 3 ++- src/main/java/envoy/client/util/EnvoyLog.java | 27 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index a6c1aaa..62d3f69 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -68,7 +68,8 @@ public class Startup { System.exit(1); } - // Set new logger levels loaded from config + // Setup logger for the envoy package + EnvoyLog.attach("envoy"); EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index 451810f..ac90cd2 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -19,17 +19,14 @@ import envoy.client.data.Config; */ public class EnvoyLog { - private static Logger root; private static FileHandler fileHandler; private static StreamHandler consoleHandler; static { + // Remove default console handler LogManager.getLogManager().reset(); - // Get root logger - root = Logger.getLogger("envoy"); - // Configure log file File logFile = new File(Config.getInstance().getHomeDirectory(), "log/envoy_user_" + new SimpleDateFormat("yyyy-MM-dd--hh-mm-mm").format(new Date()) + ".log"); @@ -43,20 +40,34 @@ public class EnvoyLog { fileHandler = new FileHandler(logFile.getAbsolutePath()); fileHandler.setLevel(Config.getInstance().getFileLevelBarrier()); fileHandler.setFormatter(formatter); - root.addHandler(fileHandler); } catch (SecurityException | IOException e) { e.printStackTrace(); } consoleHandler = new StreamHandler(System.out, formatter); consoleHandler.setLevel(Config.getInstance().getConsoleLevelBarrier()); consoleHandler.setFormatter(formatter); - root.addHandler(consoleHandler); - - root.setLevel(Level.ALL); } private EnvoyLog() {} + /** + * Configures all loggers that are contained within the hierarchy of a specific + * path + * + * @param path the path to the loggers to configure + */ + public static void attach(String path) { + // Get root logger + Logger logger = Logger.getLogger(path); + + // Add handlers + if (fileHandler != null) logger.addHandler(fileHandler); + logger.addHandler(consoleHandler); + + // Delegate logger level filtering to the handlers + logger.setLevel(Level.ALL); + } + /** * Creates a {@link Logger} with a specified name * From 353a6dd646774e50397bee5c420489304b02d8b9 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 18 Feb 2020 16:10:33 +0100 Subject: [PATCH 250/474] Updated Javadoc in EnvoyLog --- src/main/java/envoy/client/util/EnvoyLog.java | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index ac90cd2..c9ef8cd 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -9,6 +9,12 @@ import java.util.logging.*; import envoy.client.data.Config; /** + * Configures the {@link java.util.logging} API to output the log into the + * console and a log file.
+ *
+ * Call the {@link EnvoyLog#attach(String)} method to configure a part of the + * logger hierarchy.
+ *
* Project: envoy-client
* File: EnvoyLogger.java
* Created: 14 Dec 2019
@@ -52,9 +58,10 @@ public class EnvoyLog { /** * Configures all loggers that are contained within the hierarchy of a specific - * path - * + * path to use the console and file handlers. + * * @param path the path to the loggers to configure + * @since Envoy Client v0.4-alpha */ public static void attach(String path) { // Get root logger @@ -69,10 +76,11 @@ public class EnvoyLog { } /** - * Creates a {@link Logger} with a specified name + * Creates a logger for a specified class, which output will be displayed inside + * the console and written to the log file. * * @param logClass the class in which the logger is used - * @return the created {@link Logger} + * @return the created logger * @since Envoy v0.2-alpha */ public static Logger getLogger(Class logClass) { @@ -81,23 +89,17 @@ public class EnvoyLog { } /** - * @param fileLevelBarrier the severity below which logRecords will not be - * written to the log file. At or above they'll also be - * logged in a file. Can be written either in Digits - * from 0 - 1000 or with the according name of the level + * Defines the logger level required for a record to be written to the log file. + * + * @param fileLevelBarrier the log file level * @since Envoy v0.2-alpha */ - public static void setFileLevelBarrier(Level fileLevelBarrier) { - if (fileHandler != null) fileHandler.setLevel(fileLevelBarrier); - - } + public static void setFileLevelBarrier(Level fileLevelBarrier) { if (fileHandler != null) fileHandler.setLevel(fileLevelBarrier); } /** - * @param consoleLevelBarrier the severity below which logRecords will not be - * written to the console. At or above they'll also - * be logged in a file. Can be written either in - * digits from 0 - 1000 or with the according name of - * the level + * Defines the logger level required for a record to be written to the console. + * + * @param consoleLevelBarrier the console logger level * @since Envoy v0.2-alpha */ public static void setConsoleLevelBarrier(Level consoleLevelBarrier) { From 531b35f6b78f1640a4dd903ad41da4f134da0358 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 18 Feb 2020 16:34:14 +0100 Subject: [PATCH 251/474] Adjusted logging locations and levels --- src/main/java/envoy/client/data/Cache.java | 2 +- src/main/java/envoy/client/net/Client.java | 6 +++--- .../envoy/client/net/MessageStatusChangeEventProcessor.java | 2 +- src/main/java/envoy/client/net/Receiver.java | 2 +- src/main/java/envoy/client/net/WriteProxy.java | 4 ++-- src/main/java/envoy/client/ui/ChatWindow.java | 1 - .../java/envoy/client/ui/settings/GeneralSettingsPanel.java | 2 +- src/main/java/envoy/client/util/EnvoyLog.java | 1 - 8 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/envoy/client/data/Cache.java b/src/main/java/envoy/client/data/Cache.java index 078c377..a727d01 100644 --- a/src/main/java/envoy/client/data/Cache.java +++ b/src/main/java/envoy/client/data/Cache.java @@ -35,7 +35,7 @@ public class Cache implements Consumer, Serializable { */ @Override public void accept(T element) { - logger.info(String.format("Adding element %s to cache", element)); + logger.fine(String.format("Adding element %s to cache", element)); elements.offer(element); } diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 5cd1b15..7a7f960 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -77,8 +77,8 @@ public class Client implements Closeable { receiver = new Receiver(socket.getInputStream()); // Register user creation processor, contact list processor and message cache - receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); - receiver.registerProcessor(Contacts.class, contacts -> { logger.info("Acquired contacts object " + contacts); this.contacts = contacts; }); + receiver.registerProcessor(User.class, sender -> this.sender = sender); + receiver.registerProcessor(Contacts.class, contacts -> this.contacts = contacts); receiver.registerProcessor(Message.class, receivedMessageCache); receiver.registerProcessor(HandshakeRejectionEvent.class, evt -> { rejected = true; EventBus.getInstance().dispatch(evt); }); @@ -88,7 +88,6 @@ public class Client implements Closeable { new Thread(receiver).start(); // Write login credentials - logger.finest("Sending login credentials..."); SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); // Wait for a maximum of five seconds to acquire the sender object @@ -225,6 +224,7 @@ public class Client implements Closeable { private void writeObject(Object obj) throws IOException { checkOnline(); + logger.fine("Sending object " + obj); SerializationUtils.writeBytesWithLength(obj, socket.getOutputStream()); } diff --git a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java index 774b06b..8197d53 100644 --- a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java +++ b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java @@ -29,7 +29,7 @@ public class MessageStatusChangeEventProcessor implements Consumer { try { - logger.info("Sending cached " + msg); + logger.finer("Sending cached " + msg); client.sendMessage(msg); } catch (IOException e) { logger.log(Level.SEVERE, "Could not send cached message", e); } }); localDb.getStatusCache().setProcessor(evt -> { - logger.info("Sending cached " + evt); + logger.finer("Sending cached " + evt); try { client.sendEvent(evt); } catch (IOException e) { diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 3602283..22ab504 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -390,7 +390,6 @@ public class ChatWindow extends JFrame { EventBus.getInstance().register(ContactSearchResult.class, evt -> { contactsModel.clear(); final java.util.List contacts = evt.get(); - logger.info("Received contact search result " + contacts); contacts.forEach(contactsModel::add); revalidate(); repaint(); diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index fc91740..f4537b3 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -89,5 +89,5 @@ public class GeneralSettingsPanel extends SettingsPanel { } @Override - public ActionListener getOkButtonAction() { return (evt) -> {}; } + public ActionListener getOkButtonAction() { return evt -> {}; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index c9ef8cd..3cbb856 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -84,7 +84,6 @@ public class EnvoyLog { * @since Envoy v0.2-alpha */ public static Logger getLogger(Class logClass) { - // Get a logger with the specified class name return Logger.getLogger(logClass.getCanonicalName()); } From db0894dce903807ab18970a8c31752aa52709244 Mon Sep 17 00:00:00 2001 From: Haramus Samsamus Date: Sat, 22 Feb 2020 19:01:47 +0100 Subject: [PATCH 252/474] Added selection capability to ComponentList (#112) * Fixed Javadoc error in EnvoyLog * Added selection support to ComponentList using MouseListener injection * Added selection support to MessageListRenderer * Clearing selection when reselecting an already selected element --- .../envoy/client/ui/MessageListRenderer.java | 36 +++--- .../envoy/client/ui/list/ComponentList.java | 106 +++++++++++++++--- src/main/java/envoy/client/util/EnvoyLog.java | 2 +- 3 files changed, 110 insertions(+), 34 deletions(-) diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index a069721..fcb7c84 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -3,7 +3,9 @@ package envoy.client.ui; import java.awt.Dimension; import java.text.SimpleDateFormat; -import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JPanel; import envoy.client.data.Settings; import envoy.client.ui.list.ComponentList; @@ -24,18 +26,12 @@ import envoy.data.Message; public class MessageListRenderer implements ComponentListCellRenderer { @Override - public JComponent getListCellComponent(ComponentList list, Message value, boolean isSelected) { - final JPanel panel = new JPanel(); - if (isSelected) { - panel.setBackground(Color.DARK_GRAY); - panel.setForeground(Color.RED); - // TODO: Selection - // setBackground(list.getSelectionBackground()); - // setForeground(list.getSelectionForeground()); - } else { - panel.setBackground(list.getBackground()); - panel.setForeground(list.getForeground()); - } + public JPanel getListCellComponent(ComponentList list, Message value, boolean isSelected) { + final JPanel panel = new JPanel(); + final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + + // Panel background + panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); // TODO: Handle message attachments @@ -43,11 +39,11 @@ public class MessageListRenderer implements ComponentListCellRenderer { final String state = value.getStatus().toString(); final String date = new SimpleDateFormat("dd.MM.yyyy HH.mm").format(value.getCreationDate()); - // Getting the MessageColor in the Chat of the current theme - String textColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat().toHex(); + // Message text color + String textColor = theme.getMessageColorChat().toHex(); - // Getting the DateColor in the Chat of the current theme - String dateColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getDateColorChat().toHex(); + // Message date color + String dateColor = theme.getDateColorChat().toHex(); panel.add(new JLabel(String.format("

%s

%s :%s", dateColor, @@ -57,10 +53,10 @@ public class MessageListRenderer implements ComponentListCellRenderer { state))); // Define some space to the messages below - panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0), BorderFactory.createEtchedBorder())); + panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(), BorderFactory.createEtchedBorder())); - // Define a maximum height of 50px - Dimension size = new Dimension(list.getWidth() - 25, 50); + // Set the width to the list width + Dimension size = new Dimension(list.getWidth() - 25, panel.getPreferredSize().height); panel.setMaximumSize(size); panel.setMinimumSize(size); panel.setPreferredSize(size); diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 4528b98..4b26978 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -1,7 +1,10 @@ package envoy.client.ui.list; -import javax.swing.BoxLayout; -import javax.swing.JPanel; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.*; /** * Provides a vertical list layout of components provided in a @@ -21,6 +24,8 @@ public class ComponentList extends JPanel { private ComponentListModel model; private ComponentListCellRenderer renderer; + private int currentSelection = -1; + private static final long serialVersionUID = 1759644503942876737L; /** @@ -50,22 +55,22 @@ public class ComponentList extends JPanel { } /** - * Sets the list model providing the list elements to render + * Sets the list model providing the list elements to render. The rendered + * components will be synchronized with the contents of the new model or removed + * if the new model is {@code null}. * * @param model the list model to set * @since Envoy v0.3-alpha */ public void setModel(ComponentListModel model) { + // Remove old model - if (this.model != null) - this.model.setComponentList(null); + if (this.model != null) this.model.setComponentList(null); // Synchronize with new model this.model = model; - if (model != null) { - this.model.setComponentList(this); - synchronizeModel(); - } else removeAll(); + if (model != null) this.model.setComponentList(this); + synchronizeModel(); } /** @@ -76,8 +81,7 @@ public class ComponentList extends JPanel { */ public void synchronizeModel() { removeAll(); - if (model != null) for (E elem : model) - add(elem); + if (model != null) model.forEach(this::add); } /** @@ -87,7 +91,83 @@ public class ComponentList extends JPanel { * @param elem the element to add * @since Envoy v0.3-alpha */ - void add(E elem) { - add(renderer.getListCellComponent(this, elem, false)); + void add(E elem) { add(elem, getComponentCount(), false); } + + /** + * Adds an object to the list by rendering it with the current + * {@link ComponentListRenderer}. + * + * @param elem the element to add + * @param index the index at which to add the element + * @param isSelected the selection state of the element + * @since Envoy v0.1-beta + */ + private void add(E elem, int index, boolean isSelected) { + final JComponent component = renderer.getListCellComponent(this, elem, isSelected); + component.addMouseListener(getSelectionListener(index)); + add(component, index); + } + + /** + * @param componentIndex the index of the list component to which the mouse + * listener will be added + * @return a mouse listener calling the + * {@link ComponentList#componentSelected(int)} method with the + * component's index when a left click is performed by the user + * @since Envoy v0.1-beta + */ + private MouseListener getSelectionListener(int componentIndex) { + return new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { componentSelected(componentIndex); } } + }; + } + + /** + * Gets called when a list component has been clicked on by the user. Any + * previous selections are then removed and the selected component gets + * redrawn.
+ *
+ * If the currently selected component gets selected again, the selection is + * removed. + * + * @param index the index of the selected component + * @since Envoy v0.1-beta + */ + private void componentSelected(int index) { + if (index == currentSelection) { + + // Clear selection + update(currentSelection, false); + currentSelection = -1; + + } else { + + // Remove old selection + if (currentSelection >= 0) update(currentSelection, false); + + // Assign new selection + currentSelection = index; + + // Update current selection + update(currentSelection, true); + + } + + revalidate(); + repaint(); + } + + /** + * Replaces a list element with a newly rendered instance of its contents. + * + * @param index the index of the element to update + * @param isSelected the selection state passed to the {@link ListCellRenderer} + * @since Envoy v0.1-beta + */ + private void update(int index, boolean isSelected) { + remove(index); + add(model.get(index), index, isSelected); } } diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java index 3cbb856..cf2818d 100644 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ b/src/main/java/envoy/client/util/EnvoyLog.java @@ -61,7 +61,7 @@ public class EnvoyLog { * path to use the console and file handlers. * * @param path the path to the loggers to configure - * @since Envoy Client v0.4-alpha + * @since Envoy Client v0.1-beta */ public static void attach(String path) { // Get root logger From 6ffec1a3e37f94eab32371190f3880e45df726ca Mon Sep 17 00:00:00 2001 From: Haramus Samsamus Date: Thu, 5 Mar 2020 14:27:40 +0100 Subject: [PATCH 253/474] Migrated configuration and logging to Envoy Common (#113) * Moved client specific configuration to ClientConfig * Finished ClientConfig integration, checking init state in EnvoyLog * Migrated Config, ConfigItem and EnvoyLog to envoy-common * Updated envoy-common dependency to develop-SNAPSHOT --- pom.xml | 2 +- src/main/java/envoy/client/data/Cache.java | 2 +- .../data/{Config.java => ClientConfig.java} | 99 ++++------------ .../java/envoy/client/data/ConfigItem.java | 92 --------------- .../envoy/client/data/PersistentLocalDb.java | 1 + src/main/java/envoy/client/data/Settings.java | 4 +- src/main/java/envoy/client/net/Client.java | 8 +- .../MessageStatusChangeEventProcessor.java | 2 +- .../client/net/ReceivedMessageProcessor.java | 2 +- src/main/java/envoy/client/net/Receiver.java | 2 +- .../java/envoy/client/net/WriteProxy.java | 2 +- src/main/java/envoy/client/ui/ChatWindow.java | 2 +- .../java/envoy/client/ui/LoginDialog.java | 8 +- src/main/java/envoy/client/ui/Startup.java | 17 +-- .../ui/settings/GeneralSettingsPanel.java | 2 +- .../client/ui/settings/SettingsScreen.java | 2 +- .../ui/settings/ThemeCustomizationPanel.java | 2 +- src/main/java/envoy/client/util/EnvoyLog.java | 107 ------------------ 18 files changed, 50 insertions(+), 306 deletions(-) rename src/main/java/envoy/client/data/{Config.java => ClientConfig.java} (53%) delete mode 100644 src/main/java/envoy/client/data/ConfigItem.java delete mode 100644 src/main/java/envoy/client/util/EnvoyLog.java diff --git a/pom.xml b/pom.xml index e670832..ec25577 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - v0.2-alpha + develop-SNAPSHOT diff --git a/src/main/java/envoy/client/data/Cache.java b/src/main/java/envoy/client/data/Cache.java index a727d01..2622322 100644 --- a/src/main/java/envoy/client/data/Cache.java +++ b/src/main/java/envoy/client/data/Cache.java @@ -6,7 +6,7 @@ import java.util.Queue; import java.util.function.Consumer; import java.util.logging.Logger; -import envoy.client.util.EnvoyLog; +import envoy.util.EnvoyLog; /** * Stores elements in a queue to process them later.
diff --git a/src/main/java/envoy/client/data/Config.java b/src/main/java/envoy/client/data/ClientConfig.java similarity index 53% rename from src/main/java/envoy/client/data/Config.java rename to src/main/java/envoy/client/data/ClientConfig.java index 1f351ea..349fa54 100644 --- a/src/main/java/envoy/client/data/Config.java +++ b/src/main/java/envoy/client/data/ClientConfig.java @@ -2,33 +2,38 @@ package envoy.client.data; import java.io.File; import java.security.NoSuchAlgorithmException; -import java.util.*; import java.util.function.Function; import java.util.logging.Level; +import envoy.data.Config; +import envoy.data.ConfigItem; import envoy.data.LoginCredentials; -import envoy.exception.EnvoyException; /** - * Manages all application settings that are set during application startup by - * either loading them from the {@link Properties} file - * {@code client.properties} or parsing them from the command line arguments of - * the application.
+ * Implements a configuration specific to the Envoy Client with default values + * and convenience methods.
*
* Project: envoy-client
- * File: Config.java
- * Created: 12 Oct 2019
+ * File: ClientConfig.java
+ * Created: 01.03.2020
* * @author Kai S. K. Engelbart - * @since Envoy v0.1-alpha + * @since Envoy v0.1-beta */ -public class Config { +public class ClientConfig extends Config { - private Map> items = new HashMap<>(); + private static ClientConfig config; - private static Config config; + /** + * @return the singleton instance of the client config + * @since Envoy v0.1-beta + */ + public static ClientConfig getInstance() { + if (config == null) config = new ClientConfig(); + return config; + } - private Config() { + private ClientConfig() { items.put("server", new ConfigItem<>("server", "s", Function.identity(), null, true)); items.put("port", new ConfigItem<>("port", "p", Integer::parseInt, null, true)); items.put("localDB", new ConfigItem<>("localDB", "db", File::new, new File("localDB"), true)); @@ -40,72 +45,6 @@ public class Config { items.put("password", new ConfigItem<>("password", "pw", String::toCharArray)); } - /** - * @return the singleton instance of the {@link Config} - * @since Envoy v0.1-alpha - */ - public static Config getInstance() { - if (config == null) config = new Config(); - return config; - } - - /** - * Defaults to the {@code client.properties} file for information. - * This file contains information about - * the server and port, as well as the path to the local - * database and the synchronization timeout - * - * @throws EnvoyException if the {@code client.properties} file could not be - * loaded - * @since Envoy v0.1-alpha - */ - public void load() throws EnvoyException { - ClassLoader loader = getClass().getClassLoader(); - try { - Properties properties = new Properties(); - properties.load(loader.getResourceAsStream("client.properties")); - items.forEach((name, item) -> { if (properties.containsKey(name)) item.parse(properties.getProperty(name)); }); - } catch (Exception e) { - throw new EnvoyException("Failed to load client.properties", e); - } - } - - /** - * Sets the server, port and localDB path via command line properties --server / - * -s, --port / -p and --localDB / -db. - * - * @param args the command line arguments to parse - * @throws EnvoyException if the command line arguments contain an unknown token - * @since Envoy v0.1-alpha - */ - public void load(String[] args) throws EnvoyException { - for (int i = 0; i < args.length; i++) - for (ConfigItem item : items.values()) - if (args[i].startsWith("--")) { - if (args[i].length() == 2) throw new EnvoyException("Malformed command line argument at position " + i); - final String commandLong = args[i].substring(2); - if (item.getCommandLong().equals(commandLong)) { - item.parse(args[++i]); - break; - } - } else if (args[i].startsWith("-")) { - if (args[i].length() == 1) throw new EnvoyException("Malformed command line argument at position " + i); - final String commandShort = args[i].substring(1); - if (item.getCommandShort().equals(commandShort)) { - item.parse(args[++i]); - break; - } - } else throw new EnvoyException("Malformed command line argument at position " + i); - } - - /** - * @return {@code true} if all mandatory config items are initialized - * @since Envoy v0.1-alpha - */ - public boolean isInitialized() { - return items.values().stream().filter(ConfigItem::isMandatory).map(ConfigItem::get).noneMatch(Objects::isNull); - } - /** * @return the host name of the Envoy server * @since Envoy v0.1-alpha @@ -178,4 +117,4 @@ public class Config { return null; } } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/data/ConfigItem.java b/src/main/java/envoy/client/data/ConfigItem.java deleted file mode 100644 index 6a987cb..0000000 --- a/src/main/java/envoy/client/data/ConfigItem.java +++ /dev/null @@ -1,92 +0,0 @@ -package envoy.client.data; - -import java.util.function.Function; - -/** - * Contains a single {@link Config} value as well as the corresponding command - * line arguments and its default value.
- *
- * Project: envoy-clientChess
- * File: ConfigItem.javaEvent.java
- * Created: 21.12.2019
- * - * @author Kai S. K. Engelbart - * @param the type of the config item's value - * @since Envoy v0.2-alpha - */ -public class ConfigItem { - - private final String commandLong, commandShort; - private final Function parseFunction; - private final boolean mandatory; - - private T value; - - /** - * Initializes a {@link ConfigItem}. - * - * @param commandLong the long command line argument to set this value - * @param commandShort the short command line argument to set this value - * @param parseFunction the {@code Function} that parses the value - * from a string - * @param defaultValue the optional default value to set before parsing - * @param mandatory indicated that this config item must be initialized with - * a non-null value - * @since Envoy v0.2-alpha - */ - public ConfigItem(String commandLong, String commandShort, Function parseFunction, T defaultValue, boolean mandatory) { - this.commandLong = commandLong; - this.commandShort = commandShort; - this.parseFunction = parseFunction; - this.mandatory = mandatory; - value = defaultValue; - } - - /** - * Initializes an optional {@link ConfigItem} without a default value. - * - * @param commandLong the long command line argument to set this value - * @param commandShort the short command line argument to set this value - * @param parseFunction the {@code Function} that parses the value - * from a string - * @since Envoy v0.3-alpha - */ - public ConfigItem(String commandLong, String commandShort, Function parseFunction) { - this(commandLong, commandShort, parseFunction, null, false); - } - - /** - * Parses this {@ConfigItem}'s value from a string. - * - * @param input the string to parse from - * @since Envoy v0.2-alpha - */ - public void parse(String input) { value = parseFunction.apply(input); } - - /** - * @return The long command line argument to set the value of this - * {@link ConfigItem} - * @since Envoy v0.2-alpha - */ - public String getCommandLong() { return commandLong; } - - /** - * @return The short command line argument to set the value of this - * {@link ConfigItem} - * @since Envoy v0.2-alpha - */ - public String getCommandShort() { return commandShort; } - - /** - * @return the value of this {@link ConfigItem} - * @since Envoy v0.2-alpha - */ - public T get() { return value; } - - /** - * @return {@code true} if this {@link ConfigItem} is mandatory for successful - * application initialization - * @since Envoy v0.3-alpha - */ - public boolean isMandatory() { return mandatory; } -} diff --git a/src/main/java/envoy/client/data/PersistentLocalDb.java b/src/main/java/envoy/client/data/PersistentLocalDb.java index 0a04729..f59b0f2 100644 --- a/src/main/java/envoy/client/data/PersistentLocalDb.java +++ b/src/main/java/envoy/client/data/PersistentLocalDb.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import envoy.data.ConfigItem; import envoy.data.IdGenerator; import envoy.util.SerializationUtils; diff --git a/src/main/java/envoy/client/data/Settings.java b/src/main/java/envoy/client/data/Settings.java index 8cf0283..c44e4f4 100644 --- a/src/main/java/envoy/client/data/Settings.java +++ b/src/main/java/envoy/client/data/Settings.java @@ -33,12 +33,12 @@ public class Settings { /** * Settings are stored in this file. */ - private static final File settingsFile = new File(Config.getInstance().getHomeDirectory(), "settings.ser"); + private static final File settingsFile = new File(ClientConfig.getInstance().getHomeDirectory(), "settings.ser"); /** * User-defined themes are stored inside this file. */ - private static final File themeFile = new File(Config.getInstance().getHomeDirectory(), "themes.ser"); + private static final File themeFile = new File(ClientConfig.getInstance().getHomeDirectory(), "themes.ser"); /** * Singleton instance of this class. diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 7a7f960..42bfe0b 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -10,13 +10,13 @@ import java.util.logging.Logger; import javax.naming.TimeLimitExceededException; import envoy.client.data.Cache; -import envoy.client.data.Config; +import envoy.client.data.ClientConfig; import envoy.client.data.LocalDb; import envoy.client.event.SendEvent; -import envoy.client.util.EnvoyLog; import envoy.data.*; import envoy.event.*; import envoy.event.ContactOperationEvent.Operation; +import envoy.util.EnvoyLog; import envoy.util.SerializationUtils; /** @@ -45,8 +45,8 @@ public class Client implements Closeable { private volatile boolean rejected; // Configuration and logging - private static final Config config = Config.getInstance(); - private static final Logger logger = EnvoyLog.getLogger(Client.class); + private static final ClientConfig config = ClientConfig.getInstance(); + private static final Logger logger = EnvoyLog.getLogger(Client.class); /** * Enters the online mode by acquiring a user ID from the server. As a diff --git a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java index 8197d53..834bcc8 100644 --- a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java +++ b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java @@ -3,10 +3,10 @@ package envoy.client.net; import java.util.function.Consumer; import java.util.logging.Logger; -import envoy.client.util.EnvoyLog; import envoy.data.Message.MessageStatus; import envoy.event.EventBus; import envoy.event.MessageStatusChangeEvent; +import envoy.util.EnvoyLog; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/net/ReceivedMessageProcessor.java b/src/main/java/envoy/client/net/ReceivedMessageProcessor.java index 5196402..95f19c5 100644 --- a/src/main/java/envoy/client/net/ReceivedMessageProcessor.java +++ b/src/main/java/envoy/client/net/ReceivedMessageProcessor.java @@ -4,10 +4,10 @@ import java.util.function.Consumer; import java.util.logging.Logger; import envoy.client.event.MessageCreationEvent; -import envoy.client.util.EnvoyLog; import envoy.data.Message; import envoy.data.Message.MessageStatus; import envoy.event.EventBus; +import envoy.util.EnvoyLog; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/net/Receiver.java b/src/main/java/envoy/client/net/Receiver.java index 4a4fda8..3b53b48 100644 --- a/src/main/java/envoy/client/net/Receiver.java +++ b/src/main/java/envoy/client/net/Receiver.java @@ -10,7 +10,7 @@ import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; -import envoy.client.util.EnvoyLog; +import envoy.util.EnvoyLog; import envoy.util.SerializationUtils; /** diff --git a/src/main/java/envoy/client/net/WriteProxy.java b/src/main/java/envoy/client/net/WriteProxy.java index 272da8b..7d25bf1 100644 --- a/src/main/java/envoy/client/net/WriteProxy.java +++ b/src/main/java/envoy/client/net/WriteProxy.java @@ -5,9 +5,9 @@ import java.util.logging.Level; import java.util.logging.Logger; import envoy.client.data.LocalDb; -import envoy.client.util.EnvoyLog; import envoy.data.Message; import envoy.event.MessageStatusChangeEvent; +import envoy.util.EnvoyLog; /** * Implements methods to send {@link Message}s and diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 22ab504..813cd71 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -22,12 +22,12 @@ import envoy.client.net.WriteProxy; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListModel; import envoy.client.ui.settings.SettingsScreen; -import envoy.client.util.EnvoyLog; import envoy.data.Message; import envoy.data.Message.MessageStatus; import envoy.data.MessageBuilder; import envoy.data.User; import envoy.event.*; +import envoy.util.EnvoyLog; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index 7b93bdf..0c507eb 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -14,13 +14,13 @@ import javax.swing.border.EmptyBorder; import envoy.client.data.*; import envoy.client.event.HandshakeSuccessfulEvent; import envoy.client.net.Client; -import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; import envoy.data.Message; import envoy.data.User; import envoy.event.EventBus; import envoy.event.HandshakeRejectionEvent; import envoy.exception.EnvoyException; +import envoy.util.EnvoyLog; /** * Project: envoy-client
@@ -59,9 +59,9 @@ public class LoginDialog extends JDialog { private final LocalDb localDb; private final Cache receivedMessageCache; - private static final Config config = Config.getInstance(); - private static final Logger logger = EnvoyLog.getLogger(LoginDialog.class); - private static final long serialVersionUID = 352021600833907468L; + private static final ClientConfig config = ClientConfig.getInstance(); + private static final Logger logger = EnvoyLog.getLogger(LoginDialog.class); + private static final long serialVersionUID = 352021600833907468L; /** * Displays a dialog enabling the user to enter their user name and password. diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 62d3f69..81b393f 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -4,6 +4,7 @@ import java.awt.EventQueue; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; @@ -14,9 +15,10 @@ import javax.swing.SwingUtilities; import envoy.client.data.*; import envoy.client.net.Client; import envoy.client.net.WriteProxy; -import envoy.client.util.EnvoyLog; +import envoy.data.Config; import envoy.data.Message; import envoy.exception.EnvoyException; +import envoy.util.EnvoyLog; /** * Starts the Envoy client and prompts the user to enter their name.
@@ -48,13 +50,15 @@ public class Startup { * @since Envoy v0.1-alpha */ public static void main(String[] args) { - Config config = Config.getInstance(); + ClientConfig config = ClientConfig.getInstance(); SwingUtilities.invokeLater(() -> chatWindow = new ChatWindow()); try { // Load the configuration from client.properties first - config.load(); + Properties properties = new Properties(); + properties.load(Startup.class.getClassLoader().getResourceAsStream("client.properties")); + config.load(properties); // Override configuration values with command line arguments if (args.length > 0) config.load(args); @@ -62,13 +66,13 @@ public class Startup { // Check if all mandatory configuration values have been initialized if (!config.isInitialized()) throw new EnvoyException("Configuration is not fully initialized"); } catch (Exception e) { - JOptionPane - .showMessageDialog(null, "Error loading configuration values:\n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, "Error loading configuration values:\n" + e, "Configuration error", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); System.exit(1); } // Setup logger for the envoy package + EnvoyLog.initialize(config); EnvoyLog.attach("envoy"); EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); @@ -85,8 +89,7 @@ public class Startup { localDb = new PersistentLocalDb(new File(config.getHomeDirectory(), config.getLocalDB().getPath())); } catch (IOException e3) { logger.log(Level.SEVERE, "Could not initialize local database", e3); - JOptionPane - .showMessageDialog(null, "Could not initialize local database!\n" + e3, "Local database error", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, "Could not initialize local database!\n" + e3, "Local database error", JOptionPane.ERROR_MESSAGE); System.exit(1); return; } diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index f4537b3..13df564 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -13,7 +13,7 @@ import javax.swing.JTextPane; import envoy.client.data.Settings; import envoy.client.data.SettingsItem; import envoy.client.ui.Theme; -import envoy.client.util.EnvoyLog; +import envoy.util.EnvoyLog; /** * Displays GUI components that allow general settings regarding the client.
diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index a84085b..c04da96 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -13,8 +13,8 @@ import envoy.client.data.Settings; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.PrimaryButton; import envoy.client.ui.Theme; -import envoy.client.util.EnvoyLog; import envoy.event.EventBus; +import envoy.util.EnvoyLog; /** * This class provides the GUI to change the user specific settings.
diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 09a05e2..fff118f 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -13,8 +13,8 @@ import envoy.client.data.Settings; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.Color; import envoy.client.ui.Theme; -import envoy.client.util.EnvoyLog; import envoy.event.EventBus; +import envoy.util.EnvoyLog; /** * Displays GUI components that allow changing the current {@Theme} and creating diff --git a/src/main/java/envoy/client/util/EnvoyLog.java b/src/main/java/envoy/client/util/EnvoyLog.java deleted file mode 100644 index cf2818d..0000000 --- a/src/main/java/envoy/client/util/EnvoyLog.java +++ /dev/null @@ -1,107 +0,0 @@ -package envoy.client.util; - -import java.io.File; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.logging.*; - -import envoy.client.data.Config; - -/** - * Configures the {@link java.util.logging} API to output the log into the - * console and a log file.
- *
- * Call the {@link EnvoyLog#attach(String)} method to configure a part of the - * logger hierarchy.
- *
- * Project: envoy-client
- * File: EnvoyLogger.java
- * Created: 14 Dec 2019
- * - * @author Leon Hofmeister - * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha - */ -public class EnvoyLog { - - private static FileHandler fileHandler; - private static StreamHandler consoleHandler; - - static { - - // Remove default console handler - LogManager.getLogManager().reset(); - - // Configure log file - File logFile = new File(Config.getInstance().getHomeDirectory(), - "log/envoy_user_" + new SimpleDateFormat("yyyy-MM-dd--hh-mm-mm").format(new Date()) + ".log"); - logFile.getParentFile().mkdirs(); - - // Configure formatting - System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT] [%4$-7s] [%3$s] %5$s %n"); - SimpleFormatter formatter = new SimpleFormatter(); - - try { - fileHandler = new FileHandler(logFile.getAbsolutePath()); - fileHandler.setLevel(Config.getInstance().getFileLevelBarrier()); - fileHandler.setFormatter(formatter); - } catch (SecurityException | IOException e) { - e.printStackTrace(); - } - consoleHandler = new StreamHandler(System.out, formatter); - consoleHandler.setLevel(Config.getInstance().getConsoleLevelBarrier()); - consoleHandler.setFormatter(formatter); - } - - private EnvoyLog() {} - - /** - * Configures all loggers that are contained within the hierarchy of a specific - * path to use the console and file handlers. - * - * @param path the path to the loggers to configure - * @since Envoy Client v0.1-beta - */ - public static void attach(String path) { - // Get root logger - Logger logger = Logger.getLogger(path); - - // Add handlers - if (fileHandler != null) logger.addHandler(fileHandler); - logger.addHandler(consoleHandler); - - // Delegate logger level filtering to the handlers - logger.setLevel(Level.ALL); - } - - /** - * Creates a logger for a specified class, which output will be displayed inside - * the console and written to the log file. - * - * @param logClass the class in which the logger is used - * @return the created logger - * @since Envoy v0.2-alpha - */ - public static Logger getLogger(Class logClass) { - return Logger.getLogger(logClass.getCanonicalName()); - } - - /** - * Defines the logger level required for a record to be written to the log file. - * - * @param fileLevelBarrier the log file level - * @since Envoy v0.2-alpha - */ - public static void setFileLevelBarrier(Level fileLevelBarrier) { if (fileHandler != null) fileHandler.setLevel(fileLevelBarrier); } - - /** - * Defines the logger level required for a record to be written to the console. - * - * @param consoleLevelBarrier the console logger level - * @since Envoy v0.2-alpha - */ - public static void setConsoleLevelBarrier(Level consoleLevelBarrier) { - if (consoleHandler != null) consoleHandler.setLevel(consoleLevelBarrier); - } -} From 9a81fc5b064e4ae4f6217d55690bd97868260e16 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 7 Mar 2020 19:38:06 +0100 Subject: [PATCH 254/474] Changed compiler compliance to 11, modularized all packages (#114) * added module- and package-info.java, changed JRE from 8 to 11 * updated maven from Java 1.8 to 11 Co-authored-by: CyB3RC0nN0R --- .classpath | 2 +- .github/workflows/maven.yml | 4 +- .settings/org.eclipse.jdt.core.prefs | 8 +- pom.xml | 145 ++++++++++-------- .../java/envoy/client/data/package-info.java | 9 ++ .../java/envoy/client/event/package-info.java | 9 ++ src/main/java/envoy/client/net/Client.java | 2 +- src/main/java/envoy/client/net/Receiver.java | 7 +- .../java/envoy/client/net/package-info.java | 9 ++ .../client/ui/list/ComponentListModel.java | 2 +- .../envoy/client/ui/list/package-info.java | 10 ++ .../java/envoy/client/ui/package-info.java | 9 ++ .../client/ui/settings/package-info.java | 9 ++ src/main/java/module-info.java | 17 ++ 14 files changed, 163 insertions(+), 79 deletions(-) create mode 100644 src/main/java/envoy/client/data/package-info.java create mode 100644 src/main/java/envoy/client/event/package-info.java create mode 100644 src/main/java/envoy/client/net/package-info.java create mode 100644 src/main/java/envoy/client/ui/list/package-info.java create mode 100644 src/main/java/envoy/client/ui/package-info.java create mode 100644 src/main/java/envoy/client/ui/settings/package-info.java create mode 100644 src/main/java/module-info.java diff --git a/.classpath b/.classpath index a5d9509..234db15 100644 --- a/.classpath +++ b/.classpath @@ -18,7 +18,7 @@ - + diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 91106d3..da5f736 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -9,9 +9,9 @@ jobs: steps: - uses: actions/checkout@v1 - - name: Set up JDK 1.8 + - name: Set up JDK 11 uses: actions/setup-java@v1 with: - java-version: 1.8 + java-version: 11 - name: Build with Maven run: mvn -B package --file pom.xml diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index cbcb911..7d167b0 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -10,9 +10,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable.secondary= org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.compliance=11 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -87,7 +87,7 @@ org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warn org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore -org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled @@ -127,4 +127,4 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.compiler.source=11 diff --git a/pom.xml b/pom.xml index ec25577..572b5ed 100644 --- a/pom.xml +++ b/pom.xml @@ -1,68 +1,77 @@ - - 4.0.0 - - informatik-ag-ngl - envoy-client - 0.3-alpha - - Envoy Client - https://github.com/informatik-ag-ngl/envoy-client - - - UTF-8 - UTF-8 - 1.8 - 1.8 - - - - - jitpack.io - https://jitpack.io - - - - - - com.github.informatik-ag-ngl - envoy-common - develop-SNAPSHOT - - - - - envoy-client - - - src/main/resources - - - - - org.apache.maven.plugins - maven-assembly-plugin - 2.4.1 - - - package - - single - - - - - envoy.client.ui.Startup - - - - jar-with-dependencies - - - - - - - - \ No newline at end of file + + 4.0.0 + + informatik-ag-ngl + envoy-client + 0.1-beta + + Envoy Client + https://github.com/informatik-ag-ngl/envoy-client + + + UTF-8 + UTF-8 + 11 + 11 + + + + + jitpack.io + https://jitpack.io + + + + + + com.github.informatik-ag-ngl + envoy-common + develop-SNAPSHOT + + + + + envoy-client + + + src/main/resources + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.2.0 + + + package + + single + + + + + envoy.client.ui.Startup + + + + jar-with-dependencies + + + + + + + + diff --git a/src/main/java/envoy/client/data/package-info.java b/src/main/java/envoy/client/data/package-info.java new file mode 100644 index 0000000..3129027 --- /dev/null +++ b/src/main/java/envoy/client/data/package-info.java @@ -0,0 +1,9 @@ +/** + * This package contains all data classes and classes related to persistence. + * + * @author Kai S. K. Engelbart + * @author Leon Hofmeister + * @author Maximilian Käfer + * @since Envoy v0.1-beta + */ +package envoy.client.data; diff --git a/src/main/java/envoy/client/event/package-info.java b/src/main/java/envoy/client/event/package-info.java new file mode 100644 index 0000000..58383e0 --- /dev/null +++ b/src/main/java/envoy/client/event/package-info.java @@ -0,0 +1,9 @@ +/** + * This package contains all client-sided events. + * + * @author Kai S. K. Engelbart + * @author Leon Hofmeister + * @author Maximilian Käfer + * @since Envoy v0.1-beta + */ +package envoy.client.event; diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 42bfe0b..acd16e5 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -85,7 +85,7 @@ public class Client implements Closeable { rejected = false; // Start receiver - new Thread(receiver).start(); + receiver.start(); // Write login credentials SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); diff --git a/src/main/java/envoy/client/net/Receiver.java b/src/main/java/envoy/client/net/Receiver.java index 3b53b48..08ea28d 100644 --- a/src/main/java/envoy/client/net/Receiver.java +++ b/src/main/java/envoy/client/net/Receiver.java @@ -21,7 +21,7 @@ import envoy.util.SerializationUtils; * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ -public class Receiver implements Runnable { +public class Receiver extends Thread { private final InputStream in; private final Map, Consumer> processors = new HashMap<>(); @@ -33,7 +33,10 @@ public class Receiver implements Runnable { * * @param in the {@link InputStream} to parse objects from */ - public Receiver(InputStream in) { this.in = in; } + public Receiver(InputStream in) { + super("Receiver"); + this.in = in; + } @Override public void run() { diff --git a/src/main/java/envoy/client/net/package-info.java b/src/main/java/envoy/client/net/package-info.java new file mode 100644 index 0000000..5ee0e4e --- /dev/null +++ b/src/main/java/envoy/client/net/package-info.java @@ -0,0 +1,9 @@ +/** + * This package contains all classes related to client-server communication. + * + * @author Kai S. K. Engelbart + * @author Leon Hofmeister + * @author Maximilian Käfer + * @since Envoy v0.1-beta + */ +package envoy.client.net; diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java index fff3e6c..a604149 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -91,7 +91,7 @@ public final class ComponentListModel implements Iterable, Serializable { */ @Override public Iterator iterator() { - return new Iterator() { + return new Iterator<>() { Iterator iter = elements.iterator(); diff --git a/src/main/java/envoy/client/ui/list/package-info.java b/src/main/java/envoy/client/ui/list/package-info.java new file mode 100644 index 0000000..5f12ffd --- /dev/null +++ b/src/main/java/envoy/client/ui/list/package-info.java @@ -0,0 +1,10 @@ +/** + * This package defines a Swing component that can be used to display lists of + * other components to the user. + * + * @author Kai S. K. Engelbart + * @author Leon Hofmeister + * @author Maximilian Käfer + * @since Envoy v0.3-alpha + */ +package envoy.client.ui.list; diff --git a/src/main/java/envoy/client/ui/package-info.java b/src/main/java/envoy/client/ui/package-info.java new file mode 100644 index 0000000..22238af --- /dev/null +++ b/src/main/java/envoy/client/ui/package-info.java @@ -0,0 +1,9 @@ +/** + * This package contains classes defining the user interface. + * + * @author Kai S. K. Engelbart + * @author Leon Hofmeister + * @author Maximilian Käfer + * @since Envoy v0.1-beta + */ +package envoy.client.ui; diff --git a/src/main/java/envoy/client/ui/settings/package-info.java b/src/main/java/envoy/client/ui/settings/package-info.java new file mode 100644 index 0000000..bde6540 --- /dev/null +++ b/src/main/java/envoy/client/ui/settings/package-info.java @@ -0,0 +1,9 @@ +/** + * This package contains user interface classes related to the settings screen. + * + * @author Kai S. K. Engelbart + * @author Leon Hofmeister + * @author Maximilian Käfer + * @since Envoy v0.2-alpha + */ +package envoy.client.ui.settings; diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 0000000..4227885 --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,17 @@ +/** + * This module contains all classes defining the client application of the Envoy + * project. + * + * @author Kai S. K. Engelbart + * @author Leon Hofmeister + * @author Maximilian Käfer + * @since Envoy v0.1-beta + */ +module envoy { + + requires transitive envoy.common; + requires transitive java.desktop; + requires transitive java.logging; + requires transitive java.naming; + requires transitive java.prefs; +} From 198e81608b8a947b9cc71d63be943cf2a2afcbf7 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 14 Mar 2020 11:17:43 +0100 Subject: [PATCH 255/474] Added the display of multi-line messages (#115) * Added multi-line messages * Added shutdown method for LoginDialog * Fixed login bug in LoginDialog * Added a maximum length for messages * Implemented update of component list elements on resizing * Improved visual appearance of some files --- src/main/java/envoy/client/ui/ChatWindow.java | 161 +++++++++++------- src/main/java/envoy/client/ui/Color.java | 14 +- .../client/ui/ContactsSearchRenderer.java | 5 +- .../java/envoy/client/ui/LoginDialog.java | 35 +++- .../envoy/client/ui/MessageListRenderer.java | 77 ++++++--- src/main/java/envoy/client/ui/Startup.java | 1 - src/main/java/envoy/client/ui/Theme.java | 10 +- .../envoy/client/ui/list/ComponentList.java | 5 +- .../client/ui/list/ComponentListModel.java | 1 + .../ui/settings/ThemeCustomizationPanel.java | 4 +- 10 files changed, 202 insertions(+), 111 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 813cd71..70fe5f9 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,8 +1,7 @@ package envoy.client.ui; import java.awt.*; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; +import java.awt.event.*; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -41,17 +40,25 @@ import envoy.util.EnvoyLog; */ public class ChatWindow extends JFrame { + /** + * This int defines the maximum amount of chars allowed per message. Currently + * set at 200. + * + * @since Envoy 0.1-beta + */ + public static final int MAX_MESSEAGE_LENGTH = 200; + // User specific objects private Client client; private WriteProxy writeProxy; private LocalDb localDb; + private Chat currentChat; // GUI components private JPanel contentPane = new JPanel(); private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); private JList userList = new JList<>(); private DefaultListModel userListModel = new DefaultListModel<>(); - private Chat currentChat; private ComponentList messageList = new ComponentList<>(new MessageListRenderer()); private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); private JTextPane textPane = new JTextPane(); @@ -64,13 +71,13 @@ public class ChatWindow extends JFrame { private PrimaryButton addContact = new PrimaryButton("+"); // Search Contacts - private final JPanel searchPane = new JPanel(); - private final PrimaryButton cancelButton = new PrimaryButton("x"); - private final PrimaryTextArea searchField = new PrimaryTextArea(space); - private final PrimaryScrollPane possibleContacts = new PrimaryScrollPane(); - private final ContactsSearchRenderer contactRenderer = new ContactsSearchRenderer(); - private final ComponentListModel contactsModel = new ComponentListModel<>(); - private final ComponentList contactList = new ComponentList<>(contactRenderer); + private final JPanel searchPane = new JPanel(); + private final PrimaryButton cancelButton = new PrimaryButton("x"); + private final PrimaryTextArea searchField = new PrimaryTextArea(space); + private final PrimaryScrollPane scrollForPossibleContacts = new PrimaryScrollPane(); + private final ContactsSearchRenderer contactRenderer = new ContactsSearchRenderer(); + private final ComponentListModel contactsModel = new ComponentListModel<>(); + private final ComponentList contactList = new ComponentList<>(contactRenderer); private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class); @@ -98,13 +105,20 @@ public class ChatWindow extends JFrame { GridBagLayout gbl_contentPane = new GridBagLayout(); gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; gbl_contentPane.rowHeights = new int[] { 1, 1, 1, 1 }; - gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; + gbl_contentPane.columnWeights = new double[] { 0.03, 1.0, 0.1 }; gbl_contentPane.rowWeights = new double[] { 0.03, 0.001, 1.0, 0.005 }; contentPane.setLayout(gbl_contentPane); messageList.setBorder(new EmptyBorder(space, space, space, space)); scrollPane.setViewportView(messageList); + scrollPane.addComponentListener(new ComponentAdapter() { + + // updates list elements when list is resized + @Override + public void componentResized(ComponentEvent e) { messageList.synchronizeModel(); } + }); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); GridBagConstraints gbc_scrollPane = new GridBagConstraints(); gbc_scrollPane.fill = GridBagConstraints.BOTH; @@ -117,7 +131,16 @@ public class ChatWindow extends JFrame { drawChatBox(gbc_scrollPane); - // Message enter field + // MessageEnterTextArea + messageEnterTextArea.addInputMethodListener(new InputMethodListener() { + + @Override + public void inputMethodTextChanged(InputMethodEvent event) { checkMessageTextLength(); } + + @Override + public void caretPositionChanged(InputMethodEvent event) {} + }); + messageEnterTextArea.addKeyListener(new KeyAdapter() { @Override @@ -125,29 +148,31 @@ public class ChatWindow extends JFrame { if (e.getKeyCode() == KeyEvent.VK_ENTER && (Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0 || e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK)) postMessage(); + // Checking if text is too long + checkMessageTextLength(); } }); - GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); - gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; - gbc_messageEnterTextfield.gridx = 1; - gbc_messageEnterTextfield.gridy = 3; + GridBagConstraints gbc_scrollPaneForTextInput = new GridBagConstraints(); + gbc_scrollPaneForTextInput.fill = GridBagConstraints.BOTH; + gbc_scrollPaneForTextInput.gridx = 1; + gbc_scrollPaneForTextInput.gridy = 3; - gbc_messageEnterTextfield.insets = insets; + gbc_scrollPaneForTextInput.insets = insets; - contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); + contentPane.add(messageEnterTextArea, gbc_scrollPaneForTextInput); // Post Button - GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); + GridBagConstraints gbc_postButton = new GridBagConstraints(); - gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; - gbc_moveSelectionPostButton.gridx = 2; - gbc_moveSelectionPostButton.gridy = 3; + gbc_postButton.fill = GridBagConstraints.BOTH; + gbc_postButton.gridx = 2; + gbc_postButton.gridy = 3; - gbc_moveSelectionPostButton.insets = insets; + gbc_postButton.insets = insets; postButton.addActionListener((evt) -> { postMessage(); }); - contentPane.add(postButton, gbc_moveSelectionPostButton); + contentPane.add(postButton, gbc_postButton); // Settings Button GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); @@ -180,9 +205,8 @@ public class ChatWindow extends JFrame { final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); - for (int i = 0; i < contentPane.getComponents().length; i++) { - if (contentPane.getComponent(i).equals(searchPane)) { drawChatBox(gbc_scrollPane); } - } + for (int i = 0; i < contentPane.getComponents().length; i++) + if (contentPane.getComponent(i).equals(searchPane)) drawChatBox(gbc_scrollPane); if (user != null) { // Select current chat currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); @@ -248,29 +272,23 @@ public class ChatWindow extends JFrame { @Override public void removeUpdate(DocumentEvent evt) { - if (client.isOnline()) { - if (searchField.getText().isEmpty()) { - contactsModel.clear(); - revalidate(); - repaint(); - } else { - try { - client.sendEvent(new ContactSearchRequest(searchField.getText())); - } catch (IOException e) { - e.printStackTrace(); - } - } + if (client.isOnline()) if (searchField.getText().isEmpty()) { + contactsModel.clear(); + revalidate(); + repaint(); + } else try { + client.sendEvent(new ContactSearchRequest(searchField.getText())); + } catch (IOException e) { + e.printStackTrace(); } } @Override public void insertUpdate(DocumentEvent evt) { - if (client.isOnline()) { - try { - client.sendEvent(new ContactSearchRequest(searchField.getText())); - } catch (IOException e) { - e.printStackTrace(); - } + if (client.isOnline()) try { + client.sendEvent(new ContactSearchRequest(searchField.getText())); + } catch (IOException e) { + e.printStackTrace(); } } @@ -289,8 +307,8 @@ public class ChatWindow extends JFrame { searchPane.add(cancelButton, gbc_cancelButton); contactList.setModel(contactsModel); - possibleContacts.setBorder(new EmptyBorder(space, space, space, space)); - possibleContacts.setViewportView(contactList); + scrollForPossibleContacts.setBorder(new EmptyBorder(space, space, space, space)); + scrollForPossibleContacts.setViewportView(contactList); GridBagConstraints gbc_possibleContacts = new GridBagConstraints(); gbc_possibleContacts.fill = GridBagConstraints.BOTH; @@ -300,7 +318,7 @@ public class ChatWindow extends JFrame { gbc_possibleContacts.insets = insets; - searchPane.add(possibleContacts, gbc_possibleContacts); + searchPane.add(scrollForPossibleContacts, gbc_possibleContacts); // Contacts Header GridBagConstraints gbc_contactsHeader = new GridBagConstraints(); @@ -387,13 +405,15 @@ public class ChatWindow extends JFrame { }); // Listen to contact search results - EventBus.getInstance().register(ContactSearchResult.class, evt -> { - contactsModel.clear(); - final java.util.List contacts = evt.get(); - contacts.forEach(contactsModel::add); - revalidate(); - repaint(); - }); + EventBus.getInstance() + .register(ContactSearchResult.class, + evt -> { + contactsModel.clear(); + final java.util.List contacts = evt.get(); + contacts.forEach(contactsModel::add); + revalidate(); + repaint(); + }); // Add new contacts to the contact list EventBus.getInstance().register(ContactOperationEvent.class, evt -> { @@ -427,14 +447,11 @@ public class ChatWindow extends JFrame { contentPane.setBackground(theme.getBackgroundColor()); contentPane.setForeground(theme.getUserNameColor()); // messageList - // messageList.setSelectionForeground(theme.getUserNameColor()); - // messageList.setSelectionBackground(theme.getSelectionColor()); - messageList.setForeground(theme.getMessageColorChat()); + messageList.setForeground(theme.getMessageTextColor()); messageList.setBackground(theme.getCellColor()); // scrollPane scrollPane.applyTheme(theme); scrollPane.autoscroll(); - // messageEnterTextArea messageEnterTextArea.setCaretColor(theme.getTypingMessageColor()); messageEnterTextArea.setForeground(theme.getTypingMessageColor()); @@ -465,9 +482,9 @@ public class ChatWindow extends JFrame { searchField.setForeground(theme.getUserNameColor()); cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor()); - contactList.setForeground(theme.getMessageColorChat()); + contactList.setForeground(theme.getMessageTextColor()); contactList.setBackground(theme.getCellColor()); - possibleContacts.applyTheme(theme); + scrollForPossibleContacts.applyTheme(theme); } private void postMessage() { @@ -477,7 +494,7 @@ public class ChatWindow extends JFrame { } if (!messageEnterTextArea.getText().isEmpty()) try { - + checkMessageTextLength(); // Create message final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator()) .setText(messageEnterTextArea.getText()) @@ -575,4 +592,24 @@ public class ChatWindow extends JFrame { this.writeProxy = writeProxy; loadUsersAndChats(); } + + /** + * Checks whether the length of the text inside messageEnterTextArea >= + * {@link ChatWindow#MAX_MESSEAGE_LENGTH} + * and splits the text into the allowed part, if that is the case. + * + * @since Envoy v0.1-beta + */ + private void checkMessageTextLength() { + String input = messageEnterTextArea.getText(); + if (input.length() >= MAX_MESSEAGE_LENGTH) { + messageEnterTextArea.setText(input.substring(0, MAX_MESSEAGE_LENGTH - 1)); + // TODO: current notification is like being hit with a hammer, maybe it should + // be replaced with a more subtle notification + JOptionPane.showMessageDialog(messageEnterTextArea, + "the maximum length for a message has been reached", + "maximum message length reached", + JOptionPane.WARNING_MESSAGE); + } + } } diff --git a/src/main/java/envoy/client/ui/Color.java b/src/main/java/envoy/client/ui/Color.java index 18d6ca6..eabdac5 100644 --- a/src/main/java/envoy/client/ui/Color.java +++ b/src/main/java/envoy/client/ui/Color.java @@ -3,11 +3,15 @@ package envoy.client.ui; import java.awt.color.ColorSpace; /** - * Project: envoy-clientChess
- * File: Color.javaEvent.java
+ * This class further develops {@link java.awt.Color} by adding extra methods + * and more default colors. + * + * Project: envoy-client
+ * File: Color.java
* Created: 23.12.2019
- * + * * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha */ @SuppressWarnings("javadoc") public class Color extends java.awt.Color { @@ -98,11 +102,13 @@ public class Color extends java.awt.Color { /** * @return the inversion of this {@link Color} by replacing the red, green and * blue values by subtracting them form 255 + * @since Envoy v0.3-alpha */ public Color invert() { return new Color(255 - getRed(), 255 - getGreen(), 255 - getBlue()); } /** * @return the hex value of this {@link Color} + * @since Envoy v0.3-alpha */ public String toHex() { return String.format("#%02x%02x%02x", getRed(), getGreen(), getBlue()); } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java index 92f5204..83fb81d 100644 --- a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java @@ -39,9 +39,8 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { panel.setForeground(list.getForeground()); } - JLabel display = new JLabel(String.format("

%s", - Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat().toHex(), - user.getName())); + JLabel display = new JLabel(user.getName()); + display.setForeground(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageTextColor()); display.setAlignmentX(Component.LEFT_ALIGNMENT); display.setAlignmentY(Component.CENTER_ALIGNMENT); display.setFont(new Font("Arial", Font.PLAIN, 16)); diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index 0c507eb..193ae8d 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -2,6 +2,8 @@ package envoy.client.ui; import java.awt.*; import java.awt.event.ItemEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; @@ -80,20 +82,29 @@ public class LoginDialog extends JDialog { // Prepare handshake localDb.loadIdGenerator(); + addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { abortLogin(); } + }); + initUi(); okButton.addActionListener((evt) -> { try { if (registerCheckBox.isSelected()) { // Check password equality - if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) + if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) { credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), true); - else { - JOptionPane.showMessageDialog(this, "The repeated password is not the origional password!"); + performHandshake(); + } else { + JOptionPane.showMessageDialog(this, "The repeated password is not the original password!"); clearPasswordFields(); } - } else credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); - performHandshake(); + } else { + credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); + performHandshake(); + } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } @@ -105,7 +116,7 @@ public class LoginDialog extends JDialog { evt -> { clearPasswordFields(); errorMessage.setVisible(true); errorMessage.setText(evt.get()); }); // Exit the application when the dialog is cancelled - cancelButton.addActionListener(evt -> { logger.info("The login process has been cancelled. Exiting..."); System.exit(0); }); + cancelButton.addActionListener(evt -> abortLogin()); // Log in directly if configured if (config.hasLoginCredentials()) { @@ -320,4 +331,14 @@ public class LoginDialog extends JDialog { cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor()); } -} \ No newline at end of file + + /** + * Shuts the system down properly if the login was aborted. + * + * @since Envoy v0.1-beta + */ + private void abortLogin() { + logger.info("The login process has been cancelled. Exiting..."); + System.exit(0); + } +} diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index fcb7c84..6b70e1b 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -1,11 +1,10 @@ package envoy.client.ui; -import java.awt.Dimension; +import java.awt.BorderLayout; +import java.awt.Font; import java.text.SimpleDateFormat; -import javax.swing.BorderFactory; -import javax.swing.JLabel; -import javax.swing.JPanel; +import javax.swing.*; import envoy.client.data.Settings; import envoy.client.ui.list.ComponentList; @@ -21,46 +20,74 @@ import envoy.data.Message; * * @author Kai S. K. Engelbart * @author Maximilian Käfer + * @author Leon Hofmeister * @since Envoy v0.1-alpha */ public class MessageListRenderer implements ComponentListCellRenderer { + private JTextArea messageTextArea; + @Override public JPanel getListCellComponent(ComponentList list, Message value, boolean isSelected) { - final JPanel panel = new JPanel(); - final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + final JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); // Panel background panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); // TODO: Handle message attachments - final String text = value.getText(); final String state = value.getStatus().toString(); - final String date = new SimpleDateFormat("dd.MM.yyyy HH.mm").format(value.getCreationDate()); + final String date = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(value.getCreationDate()); + final String text = value.getText(); - // Message text color - String textColor = theme.getMessageColorChat().toHex(); + // The Label that displays the creation date of a message + JLabel dateLabel = new JLabel(date); + // Set the date color to be the value of DateColorChat + dateLabel.setForeground(theme.getDateColor()); - // Message date color - String dateColor = theme.getDateColorChat().toHex(); + panel.add(dateLabel, BorderLayout.NORTH); - panel.add(new JLabel(String.format("

%s

%s :%s", - dateColor, - date, - textColor, - text, - state))); + // The JTextArea that displays the text content of a message and its status + messageTextArea = new JTextArea(text + System.getProperty("line.separator")); + messageTextArea.setLineWrap(true); + messageTextArea.setWrapStyleWord(true); + messageTextArea.setAlignmentX(0.5f); + messageTextArea.setForeground(theme.getMessageTextColor()); + messageTextArea.setBackground(panel.getBackground()); + messageTextArea.setEditable(false); + + panel.add(messageTextArea, BorderLayout.CENTER); + + JLabel statusLabel = new JLabel(state); + statusLabel.setFont(new Font("Arial", Font.BOLD, 14)); + Color statusColor; + switch (value.getStatus()) { + case WAITING: + statusColor = Color.gray; + break; + case SENT: + statusColor = Color.blue; + break; + case RECEIVED: + statusColor = Color.yellow; + break; + case READ: + statusColor = Color.green; + break; + default: + statusColor = theme.getMessageTextColor(); + break; + } + statusLabel.setForeground(statusColor); + statusLabel.setBackground(panel.getBackground()); + + panel.add(statusLabel, BorderLayout.SOUTH); // Define some space to the messages below panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(), BorderFactory.createEtchedBorder())); - // Set the width to the list width - Dimension size = new Dimension(list.getWidth() - 25, panel.getPreferredSize().height); - panel.setMaximumSize(size); - panel.setMinimumSize(size); - panel.setPreferredSize(size); - return panel; } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 81b393f..8202941 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -51,7 +51,6 @@ public class Startup { */ public static void main(String[] args) { ClientConfig config = ClientConfig.getInstance(); - SwingUtilities.invokeLater(() -> chatWindow = new ChatWindow()); try { diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index d912988..2956882 100644 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -85,16 +85,18 @@ public class Theme implements Serializable { public Color getInteractableForegroundColor() { return colors.get("interactableForegroundColor"); } /** - * @return messageColorChat + * @return the {@link Color} in which the text content of a message should be + * displayed * @since Envoy v0.2-alpha */ - public Color getMessageColorChat() { return colors.get("messageColorChat"); } + public Color getMessageTextColor() { return colors.get("messageColorChat"); } /** - * @return dateColorChat + * @return the {@link Color} in which the creation date of a message should be + * displayed * @since Envoy v0.2-alpha */ - public Color getDateColorChat() { return colors.get("dateColorChat"); } + public Color getDateColor() { return colors.get("dateColorChat"); } /** * @return selectionColor diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 4b26978..9b5b749 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -82,6 +82,7 @@ public class ComponentList extends JPanel { public void synchronizeModel() { removeAll(); if (model != null) model.forEach(this::add); + revalidate(); } /** @@ -120,7 +121,7 @@ public class ComponentList extends JPanel { return new MouseAdapter() { @Override - public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { componentSelected(componentIndex); } } + public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) componentSelected(componentIndex); } }; } @@ -141,7 +142,6 @@ public class ComponentList extends JPanel { // Clear selection update(currentSelection, false); currentSelection = -1; - } else { // Remove old selection @@ -152,7 +152,6 @@ public class ComponentList extends JPanel { // Update current selection update(currentSelection, true); - } revalidate(); diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java index a604149..62a8643 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -34,6 +34,7 @@ public final class ComponentListModel implements Iterable, Serializable { */ public boolean add(E e) { if (componentList != null) componentList.add(e); + componentList.revalidate(); return elements.add(e); } diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index fff118f..a2aca9a 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -181,8 +181,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor", 2); buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3); buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor", 4); - buildCustomizeElement(theme, theme.getMessageColorChat(), "Messages Chat", "messageColorChat", 5); - buildCustomizeElement(theme, theme.getDateColorChat(), "Date Chat", "dateColorChat", 6); + buildCustomizeElement(theme, theme.getMessageTextColor(), "Messages Chat", "messageColorChat", 5); + buildCustomizeElement(theme, theme.getDateColor(), "Date Chat", "dateColorChat", 6); buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor", 7); buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor", 8); buildCustomizeElement(theme, theme.getUserNameColor(), "User Names", "userNameColor", 9); From bd1563b439fcaefd34c91e84088d599fc90b7771 Mon Sep 17 00:00:00 2001 From: Haramus Samsamus Date: Sat, 14 Mar 2020 16:58:19 +0100 Subject: [PATCH 256/474] Fixed state errors in offline mode (#116) * Display all contacts as offline while in offline mode * Update message status to sent after relaying message cache --- src/main/java/envoy/client/data/LocalDb.java | 19 +++++++++- .../java/envoy/client/net/WriteProxy.java | 3 ++ src/main/java/envoy/client/ui/ChatWindow.java | 38 ++++++++----------- src/main/java/envoy/client/ui/Startup.java | 10 ++++- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/main/java/envoy/client/data/LocalDb.java b/src/main/java/envoy/client/data/LocalDb.java index 8034e2a..dd1db3a 100644 --- a/src/main/java/envoy/client/data/LocalDb.java +++ b/src/main/java/envoy/client/data/LocalDb.java @@ -21,8 +21,8 @@ import envoy.event.MessageStatusChangeEvent; public abstract class LocalDb { protected User user; - protected Map users = new HashMap<>(); - protected List chats = new ArrayList<>(); + protected Map users = new HashMap<>(); + protected List chats = new ArrayList<>(); protected IdGenerator idGenerator; protected Cache messageCache = new Cache<>(); protected Cache statusCache = new Cache<>(); @@ -143,4 +143,19 @@ public abstract class LocalDb { * @since Envoy v0.3-alpha */ public void setStatusCache(Cache statusCache) { this.statusCache = statusCache; } + + /** + * Searches for a message by ID. + * + * @param id the ID of the message to search for + * @return the message with the corresponding ID, or {@code null} if no message + * has been found + * @since Envoy v0.1-beta + */ + public Message getMessage(long id) { + for (Chat c : chats) + for (Message m : c.getModel()) + if (m.getId() == id) return m; + return null; + } } diff --git a/src/main/java/envoy/client/net/WriteProxy.java b/src/main/java/envoy/client/net/WriteProxy.java index 7d25bf1..0ba5110 100644 --- a/src/main/java/envoy/client/net/WriteProxy.java +++ b/src/main/java/envoy/client/net/WriteProxy.java @@ -47,6 +47,9 @@ public class WriteProxy { try { logger.finer("Sending cached " + msg); client.sendMessage(msg); + + // Update message state to SENT in local db + localDb.getMessage(msg.getId()).nextStatus(); } catch (IOException e) { logger.log(Level.SEVERE, "Could not send cached message", e); } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 70fe5f9..bfafc06 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -522,28 +522,6 @@ public class ChatWindow extends JFrame { } } - /** - * Initializes the elements of the user list by downloading them from the - * server. - * - * @since Envoy v0.1-alpha - */ - private void loadUsersAndChats() { - new Thread(() -> { - localDb.getUsers().values().forEach(user -> { - userListModel.addElement(user); - - // Check if user exists in local DB - if (localDb.getChats().stream().filter(c -> c.getRecipient().getId() == user.getId()).count() == 0) - localDb.getChats().add(new Chat(user)); - }); - SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); - - revalidate(); - repaint(); - }).start(); - } - private void readCurrentChat() { try { currentChat.read(writeProxy); @@ -590,7 +568,21 @@ public class ChatWindow extends JFrame { this.client = client; this.localDb = localDb; this.writeProxy = writeProxy; - loadUsersAndChats(); + + // Load users and chats + new Thread(() -> { + localDb.getUsers().values().forEach(user -> { + userListModel.addElement(user); + + // Check if user exists in local DB + if (localDb.getChats().stream().noneMatch(c -> c.getRecipient().getId() == user.getId())) + localDb.getChats().add(new Chat(user)); + }); + SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); + + revalidate(); + repaint(); + }).start(); } /** diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 8202941..98a8ffc 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -17,6 +17,7 @@ import envoy.client.net.Client; import envoy.client.net.WriteProxy; import envoy.data.Config; import envoy.data.Message; +import envoy.data.User.UserStatus; import envoy.exception.EnvoyException; import envoy.util.EnvoyLog; @@ -113,7 +114,7 @@ public class Startup { } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, - "Error while loading local database: " + e + "\nChats might not be stored locally.", + "Error while loading local database: " + e + "\nChats will not be stored locally.", "Local DB error", JOptionPane.WARNING_MESSAGE); } @@ -121,10 +122,15 @@ public class Startup { // Initialize write proxy final WriteProxy writeProxy = client.createWriteProxy(localDb); - // Save all users to the local database and flush cache if (client.isOnline()) { + + // Save all users to the local database and flush cache localDb.setUsers(client.getUsers()); writeProxy.flushCache(); + } else { + + // Set all contacts to offline mode + localDb.getUsers().values().stream().filter(u -> u != localDb.getUser()).forEach(u -> u.setStatus(UserStatus.OFFLINE)); } // Display ChatWindow and StatusTrayIcon From 1fef10769f1845a22b834fd782a8223b94a65f57 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 14 Mar 2020 17:04:51 +0100 Subject: [PATCH 257/474] fixed typo --- src/main/java/envoy/client/ui/ChatWindow.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index bfafc06..6a5ae38 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -46,7 +46,7 @@ public class ChatWindow extends JFrame { * * @since Envoy 0.1-beta */ - public static final int MAX_MESSEAGE_LENGTH = 200; + public static final int MAX_MESSAGE_LENGTH = 200; // User specific objects private Client client; @@ -575,8 +575,7 @@ public class ChatWindow extends JFrame { userListModel.addElement(user); // Check if user exists in local DB - if (localDb.getChats().stream().noneMatch(c -> c.getRecipient().getId() == user.getId())) - localDb.getChats().add(new Chat(user)); + if (localDb.getChats().stream().noneMatch(c -> c.getRecipient().getId() == user.getId())) localDb.getChats().add(new Chat(user)); }); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); @@ -587,15 +586,15 @@ public class ChatWindow extends JFrame { /** * Checks whether the length of the text inside messageEnterTextArea >= - * {@link ChatWindow#MAX_MESSEAGE_LENGTH} + * {@link ChatWindow#MAX_MESSAGE_LENGTH} * and splits the text into the allowed part, if that is the case. * * @since Envoy v0.1-beta */ private void checkMessageTextLength() { String input = messageEnterTextArea.getText(); - if (input.length() >= MAX_MESSEAGE_LENGTH) { - messageEnterTextArea.setText(input.substring(0, MAX_MESSEAGE_LENGTH - 1)); + if (input.length() >= MAX_MESSAGE_LENGTH) { + messageEnterTextArea.setText(input.substring(0, MAX_MESSAGE_LENGTH - 1)); // TODO: current notification is like being hit with a hammer, maybe it should // be replaced with a more subtle notification JOptionPane.showMessageDialog(messageEnterTextArea, From b46bfd1181ef228d5c5bd9c772cfcb77252d1f35 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 14 Mar 2020 17:10:11 +0100 Subject: [PATCH 258/474] Fixed NullPointerException caused by ComponentListModel --- src/main/java/envoy/client/ui/list/ComponentListModel.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java index 62a8643..95775c1 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -33,8 +33,10 @@ public final class ComponentListModel implements Iterable, Serializable { * @since Envoy v0.3-alpha */ public boolean add(E e) { - if (componentList != null) componentList.add(e); - componentList.revalidate(); + if (componentList != null) { + componentList.add(e); + componentList.revalidate(); + } return elements.add(e); } From 99441b770fde11b9be8432f0d79d4887ab8498ce Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 14 Mar 2020 19:59:37 +0100 Subject: [PATCH 259/474] added newline at EOF for any file not having one at its end --- pom.xml | 2 +- src/main/java/envoy/client/data/Chat.java | 12 ++++----- .../envoy/client/data/PersistentLocalDb.java | 2 +- src/main/java/envoy/client/data/Settings.java | 2 +- src/main/java/envoy/client/net/Receiver.java | 2 +- .../client/ui/ContactsSearchRenderer.java | 2 +- .../java/envoy/client/ui/PrimaryButton.java | 2 +- .../envoy/client/ui/PrimaryToggleSwitch.java | 6 ++--- src/main/java/envoy/client/ui/Startup.java | 6 ++--- .../java/envoy/client/ui/StatusTrayIcon.java | 2 +- .../envoy/client/ui/UserListRenderer.java | 2 +- .../ui/settings/GeneralSettingsPanel.java | 2 +- .../client/ui/settings/NewThemeScreen.java | 12 +++++---- .../client/ui/settings/SettingsScreen.java | 2 +- .../ui/settings/ThemeCustomizationPanel.java | 26 +++++++------------ 15 files changed, 36 insertions(+), 46 deletions(-) diff --git a/pom.xml b/pom.xml index 572b5ed..1ffd41f 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - develop-SNAPSHOT + f~forwarding_messages-SNAPSHOT diff --git a/src/main/java/envoy/client/data/Chat.java b/src/main/java/envoy/client/data/Chat.java index 49083a7..30b6bc6 100644 --- a/src/main/java/envoy/client/data/Chat.java +++ b/src/main/java/envoy/client/data/Chat.java @@ -61,12 +61,10 @@ public class Chat implements Serializable { public void read(WriteProxy writeProxy) throws IOException { for (int i = model.size() - 1; i >= 0; --i) { final Message m = model.get(i); - if (m.getSenderId() == recipient.getId()) { - if (m.getStatus() == MessageStatus.READ) break; - else { - m.setStatus(MessageStatus.READ); - writeProxy.writeMessageStatusChangeEvent(new MessageStatusChangeEvent(m)); - } + if (m.getSenderId() == recipient.getId()) if (m.getStatus() == MessageStatus.READ) break; + else { + m.setStatus(MessageStatus.READ); + writeProxy.writeMessageStatusChangeEvent(new MessageStatusChangeEvent(m)); } } } @@ -89,4 +87,4 @@ public class Chat implements Serializable { * @since Envoy v0.1-alpha */ public User getRecipient() { return recipient; } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/data/PersistentLocalDb.java b/src/main/java/envoy/client/data/PersistentLocalDb.java index f59b0f2..52d5c63 100644 --- a/src/main/java/envoy/client/data/PersistentLocalDb.java +++ b/src/main/java/envoy/client/data/PersistentLocalDb.java @@ -100,4 +100,4 @@ public class PersistentLocalDb extends LocalDb { idGenerator = SerializationUtils.read(idGeneratorFile, IdGenerator.class); } catch (ClassNotFoundException | IOException e) {} } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/data/Settings.java b/src/main/java/envoy/client/data/Settings.java index c44e4f4..89dea67 100644 --- a/src/main/java/envoy/client/data/Settings.java +++ b/src/main/java/envoy/client/data/Settings.java @@ -190,4 +190,4 @@ public class Settings { * @since Envoy v0.3-alpha */ public Theme getTheme(String themeName) { return themes.get(themeName); } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/net/Receiver.java b/src/main/java/envoy/client/net/Receiver.java index 08ea28d..d49fd93 100644 --- a/src/main/java/envoy/client/net/Receiver.java +++ b/src/main/java/envoy/client/net/Receiver.java @@ -85,4 +85,4 @@ public class Receiver extends Thread { * Removes all object processors registered at this {@link Receiver}. */ public void removeAllProcessors() { processors.clear(); } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java index 83fb81d..aa96b62 100644 --- a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/ContactsSearchRenderer.java @@ -74,4 +74,4 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { return panel; } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/PrimaryButton.java b/src/main/java/envoy/client/ui/PrimaryButton.java index 65c52a0..3486acd 100644 --- a/src/main/java/envoy/client/ui/PrimaryButton.java +++ b/src/main/java/envoy/client/ui/PrimaryButton.java @@ -60,4 +60,4 @@ public class PrimaryButton extends JButton { * @since Envoy 0.2-alpha */ public void setArcSize(int arcSize) { this.arcSize = arcSize; } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 3f58e2e..7b4f41f 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -15,7 +15,7 @@ import envoy.client.data.SettingsItem; * Project: envoy-client
* File: PrimaryToggleSwitch.java
* Created: 21 Dec 2019
- * + * * @author Maximilian Käfer * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha @@ -28,7 +28,7 @@ public class PrimaryToggleSwitch extends JButton { /** * Initializes a {@link PrimaryToggleSwitch}. - * + * * @param settingsItem the {@link SettingsItem} that is controlled by this * {@link PrimaryToggleSwitch} * @since Envoy v0.3-alpha @@ -54,4 +54,4 @@ public class PrimaryToggleSwitch extends JButton { g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25); } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 98a8ffc..8f44c2a 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -127,11 +127,9 @@ public class Startup { // Save all users to the local database and flush cache localDb.setUsers(client.getUsers()); writeProxy.flushCache(); - } else { - + } else // Set all contacts to offline mode localDb.getUsers().values().stream().filter(u -> u != localDb.getUser()).forEach(u -> u.setStatus(UserStatus.OFFLINE)); - } // Display ChatWindow and StatusTrayIcon EventQueue.invokeLater(() -> { @@ -173,4 +171,4 @@ public class Startup { } })); } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 4513aea..02e5629 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -94,4 +94,4 @@ public class StatusTrayIcon { throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); } } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index c43eeb6..2bdefca 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -59,4 +59,4 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { } return this; } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index 13df564..c85c048 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -90,4 +90,4 @@ public class GeneralSettingsPanel extends SettingsPanel { @Override public ActionListener getOkButtonAction() { return evt -> {}; } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java index 02dd42a..e30adc9 100644 --- a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java +++ b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java @@ -42,10 +42,12 @@ public class NewThemeScreen extends JDialog { * Creates a window, where you can choose a name for a new {@link Theme}.
* There are two versions of this Window. The first one is responsible for * choosing the name, the second one appears, if the name already exists. - * - * @param parent the dialog is launched with its location relative to this {@link SettingsScreen} - * @param newThemeAction is executed when a new theme name is entered - * @param modifyThemeAction is executed when an existing theme name is entered and confirmed + * + * @param parent the dialog is launched with its location relative to + * this {@link SettingsScreen} + * @param newThemeAction is executed when a new theme name is entered + * @param modifyThemeAction is executed when an existing theme name is entered + * and confirmed * @since Envoy v0.3-alpha */ public NewThemeScreen(SettingsScreen parent, Consumer newThemeAction, Consumer modifyThemeAction) { @@ -223,4 +225,4 @@ public class NewThemeScreen extends JDialog { overwrite.addActionListener((evt) -> { modifyThemeAction.accept(nameEnterTextArea.getText()); dispose(); }); } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index c04da96..56e8cf4 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -189,4 +189,4 @@ public class SettingsScreen extends JDialog { options.setForeground(theme.getUserNameColor()); options.setBackground(theme.getCellColor()); } -} \ No newline at end of file +} diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index a2aca9a..8772064 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -2,8 +2,6 @@ package envoy.client.ui.settings; import java.awt.*; import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; import java.util.logging.Level; import java.util.logging.Logger; @@ -100,17 +98,13 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.setBackground(theme.getCellColor()); // Apply theme upon selection - themes.addItemListener(new ItemListener() { + themes.addItemListener(e -> { + String selectedValue = (String) themes.getSelectedItem(); + logger.log(Level.FINEST, "Selected theme: " + selectedValue); - @Override - public void itemStateChanged(ItemEvent e) { - String selectedValue = (String) themes.getSelectedItem(); - logger.log(Level.FINEST, "Selected theme: " + selectedValue); - - final Theme currentTheme = Settings.getInstance().getTheme(selectedValue); - Settings.getInstance().setCurrentTheme(selectedValue); - EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); - } + final Theme currentTheme = Settings.getInstance().getTheme(selectedValue); + Settings.getInstance().setCurrentTheme(selectedValue); + EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); }); // Apply current theme @@ -143,11 +137,9 @@ public class ThemeCustomizationPanel extends SettingsPanel { }, name -> { // Modify theme Settings.getInstance().getThemes().replace(name, new Theme(name, temporaryTheme)); - if (themes.getSelectedItem().equals(name)) { + if (themes.getSelectedItem().equals(name)) EventBus.getInstance().dispatch(new ThemeChangeEvent(Settings.getInstance().getTheme(name))); - } else { - themes.setSelectedItem(name); - } + else themes.setSelectedItem(name); }).setVisible(true); themeChanged = false; } @@ -232,4 +224,4 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.add(button, gbc_button); } -} \ No newline at end of file +} From 384329d00d13e2ebb95fb03caa674f8aa9d97f24 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 14 Mar 2020 21:34:17 +0100 Subject: [PATCH 260/474] Created packages ui.renderer and ui.primary --- .../java/envoy/client/data/SettingsItem.java | 2 +- src/main/java/envoy/client/ui/ChatWindow.java | 14 + .../java/envoy/client/ui/LoginDialog.java | 1 + .../ui/{ => primary}/PrimaryButton.java | 126 ++--- .../ui/{ => primary}/PrimaryScrollBar.java | 3 +- .../ui/{ => primary}/PrimaryScrollPane.java | 4 +- .../ui/{ => primary}/PrimaryTextArea.java | 2 +- .../ui/{ => primary}/PrimaryToggleSwitch.java | 115 ++--- .../envoy/client/ui/primary/package-info.java | 17 + .../ContactsSearchRenderer.java | 4 +- .../{ => renderer}/MessageListRenderer.java | 39 +- .../ui/{ => renderer}/UserListRenderer.java | 2 +- .../client/ui/renderer/package-info.java | 14 + .../client/ui/settings/NewThemeScreen.java | 456 +++++++++--------- .../client/ui/settings/SettingsScreen.java | 2 +- 15 files changed, 440 insertions(+), 361 deletions(-) rename src/main/java/envoy/client/ui/{ => primary}/PrimaryButton.java (94%) rename src/main/java/envoy/client/ui/{ => primary}/PrimaryScrollBar.java (98%) rename src/main/java/envoy/client/ui/{ => primary}/PrimaryScrollPane.java (97%) rename src/main/java/envoy/client/ui/{ => primary}/PrimaryTextArea.java (98%) rename src/main/java/envoy/client/ui/{ => primary}/PrimaryToggleSwitch.java (95%) create mode 100644 src/main/java/envoy/client/ui/primary/package-info.java rename src/main/java/envoy/client/ui/{ => renderer}/ContactsSearchRenderer.java (95%) rename src/main/java/envoy/client/ui/{ => renderer}/MessageListRenderer.java (70%) rename src/main/java/envoy/client/ui/{ => renderer}/UserListRenderer.java (98%) create mode 100644 src/main/java/envoy/client/ui/renderer/package-info.java diff --git a/src/main/java/envoy/client/data/SettingsItem.java b/src/main/java/envoy/client/data/SettingsItem.java index 57ba600..cd85c71 100644 --- a/src/main/java/envoy/client/data/SettingsItem.java +++ b/src/main/java/envoy/client/data/SettingsItem.java @@ -7,7 +7,7 @@ import java.util.function.Consumer; import javax.swing.JComponent; -import envoy.client.ui.PrimaryToggleSwitch; +import envoy.client.ui.primary.PrimaryToggleSwitch; /** * Encapsulates a persistent value that is directly or indirectly mutable by the diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 6a5ae38..2db2d3d 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -20,6 +20,12 @@ import envoy.client.net.Client; import envoy.client.net.WriteProxy; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListModel; +import envoy.client.ui.primary.PrimaryButton; +import envoy.client.ui.primary.PrimaryScrollPane; +import envoy.client.ui.primary.PrimaryTextArea; +import envoy.client.ui.renderer.ContactsSearchRenderer; +import envoy.client.ui.renderer.MessageListRenderer; +import envoy.client.ui.renderer.UserListRenderer; import envoy.client.ui.settings.SettingsScreen; import envoy.data.Message; import envoy.data.Message.MessageStatus; @@ -110,7 +116,15 @@ public class ChatWindow extends JFrame { contentPane.setLayout(gbl_contentPane); messageList.setBorder(new EmptyBorder(space, space, space, space)); + messageList.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.isPopupTrigger()) { + + } + } + }); scrollPane.setViewportView(messageList); scrollPane.addComponentListener(new ComponentAdapter() { diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java index 193ae8d..9cd645d 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -16,6 +16,7 @@ import javax.swing.border.EmptyBorder; import envoy.client.data.*; import envoy.client.event.HandshakeSuccessfulEvent; import envoy.client.net.Client; +import envoy.client.ui.primary.PrimaryButton; import envoy.data.LoginCredentials; import envoy.data.Message; import envoy.data.User; diff --git a/src/main/java/envoy/client/ui/PrimaryButton.java b/src/main/java/envoy/client/ui/primary/PrimaryButton.java similarity index 94% rename from src/main/java/envoy/client/ui/PrimaryButton.java rename to src/main/java/envoy/client/ui/primary/PrimaryButton.java index 3486acd..efcfd9f 100644 --- a/src/main/java/envoy/client/ui/PrimaryButton.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryButton.java @@ -1,63 +1,63 @@ -package envoy.client.ui; - -import java.awt.Graphics; - -import javax.swing.JButton; - -/** - * Project: envoy-client
- * File: PrimaryButton.javaEvent.java
- * Created: 07.12.2019
- * - * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @since Envoy v0.2-alpha - */ -public class PrimaryButton extends JButton { - - private static final long serialVersionUID = 3662266120667728364L; - - private int arcSize; - - /** - * Creates a primary button - * - * @param title the title of the button - * @since Envoy 0.2-alpha - */ - public PrimaryButton(String title) { this(title, 6); } - - /** - * Creates a primary button - * - * @param title the title of the button - * @param arcSize the size of the arc used to draw the round button edges - * @since Envoy 0.2-alpha - */ - public PrimaryButton(String title, int arcSize) { - super(title); - setBorderPainted(false); - setFocusPainted(false); - setContentAreaFilled(false); - this.arcSize = arcSize; - } - - @Override - protected void paintComponent(Graphics g) { - g.setColor(getBackground()); - g.fillRoundRect(0, 0, getWidth(), getHeight(), arcSize, arcSize); - super.paintComponent(g); - } - - /** - * @return the arcSize - * @since Envoy 0.2-alpha - */ - public int getArcSize() { return arcSize; } - - /** - * @param arcSize the arcSize to set - * @since Envoy 0.2-alpha - */ - public void setArcSize(int arcSize) { this.arcSize = arcSize; } -} +package envoy.client.ui.primary; + +import java.awt.Graphics; + +import javax.swing.JButton; + +/** + * Project: envoy-client
+ * File: PrimaryButton.javaEvent.java
+ * Created: 07.12.2019
+ * + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.2-alpha + */ +public class PrimaryButton extends JButton { + + private static final long serialVersionUID = 3662266120667728364L; + + private int arcSize; + + /** + * Creates a primary button + * + * @param title the title of the button + * @since Envoy 0.2-alpha + */ + public PrimaryButton(String title) { this(title, 6); } + + /** + * Creates a primary button + * + * @param title the title of the button + * @param arcSize the size of the arc used to draw the round button edges + * @since Envoy 0.2-alpha + */ + public PrimaryButton(String title, int arcSize) { + super(title); + setBorderPainted(false); + setFocusPainted(false); + setContentAreaFilled(false); + this.arcSize = arcSize; + } + + @Override + protected void paintComponent(Graphics g) { + g.setColor(getBackground()); + g.fillRoundRect(0, 0, getWidth(), getHeight(), arcSize, arcSize); + super.paintComponent(g); + } + + /** + * @return the arcSize + * @since Envoy 0.2-alpha + */ + public int getArcSize() { return arcSize; } + + /** + * @param arcSize the arcSize to set + * @since Envoy 0.2-alpha + */ + public void setArcSize(int arcSize) { this.arcSize = arcSize; } +} diff --git a/src/main/java/envoy/client/ui/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java similarity index 98% rename from src/main/java/envoy/client/ui/PrimaryScrollBar.java rename to src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java index 8e8131c..7dd560e 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java @@ -1,4 +1,4 @@ -package envoy.client.ui; +package envoy.client.ui.primary; import java.awt.Color; import java.awt.Dimension; @@ -13,6 +13,7 @@ import javax.swing.JScrollBar; import javax.swing.plaf.basic.BasicScrollBarUI; import envoy.client.data.Settings; +import envoy.client.ui.Theme; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/ui/PrimaryScrollPane.java b/src/main/java/envoy/client/ui/primary/PrimaryScrollPane.java similarity index 97% rename from src/main/java/envoy/client/ui/PrimaryScrollPane.java rename to src/main/java/envoy/client/ui/primary/PrimaryScrollPane.java index f8e4dbc..47c2abb 100644 --- a/src/main/java/envoy/client/ui/PrimaryScrollPane.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryScrollPane.java @@ -1,7 +1,9 @@ -package envoy.client.ui; +package envoy.client.ui.primary; import javax.swing.JScrollPane; +import envoy.client.ui.Theme; + /** * Project: envoy-client
* File: PrimaryScrollPane.java
diff --git a/src/main/java/envoy/client/ui/PrimaryTextArea.java b/src/main/java/envoy/client/ui/primary/PrimaryTextArea.java similarity index 98% rename from src/main/java/envoy/client/ui/PrimaryTextArea.java rename to src/main/java/envoy/client/ui/primary/PrimaryTextArea.java index 29ed2f9..9f6a7ce 100644 --- a/src/main/java/envoy/client/ui/PrimaryTextArea.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryTextArea.java @@ -1,4 +1,4 @@ -package envoy.client.ui; +package envoy.client.ui.primary; import java.awt.Font; import java.awt.Graphics; diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java similarity index 95% rename from src/main/java/envoy/client/ui/PrimaryToggleSwitch.java rename to src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java index 7b4f41f..30ee098 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java @@ -1,57 +1,58 @@ -package envoy.client.ui; - -import java.awt.Dimension; -import java.awt.Graphics; - -import javax.swing.JButton; - -import envoy.client.data.Settings; -import envoy.client.data.SettingsItem; - -/** - * This component can be used to toggle between two options. This will change - * the state of a {@code boolean} {@link SettingsItem}.
- *
- * Project: envoy-client
- * File: PrimaryToggleSwitch.java
- * Created: 21 Dec 2019
- * - * @author Maximilian Käfer - * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha - */ -public class PrimaryToggleSwitch extends JButton { - - private boolean state; - - private static final long serialVersionUID = -721155303106833184L; - - /** - * Initializes a {@link PrimaryToggleSwitch}. - * - * @param settingsItem the {@link SettingsItem} that is controlled by this - * {@link PrimaryToggleSwitch} - * @since Envoy v0.3-alpha - */ - public PrimaryToggleSwitch(SettingsItem settingsItem) { - setPreferredSize(new Dimension(50, 25)); - setMinimumSize(new Dimension(50, 25)); - setMaximumSize(new Dimension(50, 25)); - - setBorderPainted(false); - setFocusPainted(false); - setContentAreaFilled(false); - - state = settingsItem.get(); - addActionListener((evt) -> { state = !state; settingsItem.set(state); revalidate(); repaint(); }); - } - - @Override - public void paintComponent(Graphics g) { - g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY); - g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25); - - g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); - g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25); - } -} +package envoy.client.ui.primary; + +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.swing.JButton; + +import envoy.client.data.Settings; +import envoy.client.data.SettingsItem; +import envoy.client.ui.Color; + +/** + * This component can be used to toggle between two options. This will change + * the state of a {@code boolean} {@link SettingsItem}.
+ *
+ * Project: envoy-client
+ * File: PrimaryToggleSwitch.java
+ * Created: 21 Dec 2019
+ * + * @author Maximilian Käfer + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class PrimaryToggleSwitch extends JButton { + + private boolean state; + + private static final long serialVersionUID = -721155303106833184L; + + /** + * Initializes a {@link PrimaryToggleSwitch}. + * + * @param settingsItem the {@link SettingsItem} that is controlled by this + * {@link PrimaryToggleSwitch} + * @since Envoy v0.3-alpha + */ + public PrimaryToggleSwitch(SettingsItem settingsItem) { + setPreferredSize(new Dimension(50, 25)); + setMinimumSize(new Dimension(50, 25)); + setMaximumSize(new Dimension(50, 25)); + + setBorderPainted(false); + setFocusPainted(false); + setContentAreaFilled(false); + + state = settingsItem.get(); + addActionListener((evt) -> { state = !state; settingsItem.set(state); revalidate(); repaint(); }); + } + + @Override + public void paintComponent(Graphics g) { + g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY); + g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25); + + g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); + g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25); + } +} diff --git a/src/main/java/envoy/client/ui/primary/package-info.java b/src/main/java/envoy/client/ui/primary/package-info.java new file mode 100644 index 0000000..8ede25f --- /dev/null +++ b/src/main/java/envoy/client/ui/primary/package-info.java @@ -0,0 +1,17 @@ +/** + * This package defines all "primary" components that were defined specifically + * for the visual improvement of Envoy. However, they can still be used in + * general for other projects.
+ * Primary elements are supposed to provide the main functionality of a UI + * component.
+ *
+ * Project: envoy-client
+ * File: package-info.java
+ * Created: 14 Mar 2020
+ * + * @author Leon Hofmeister + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.1-beta + */ +package envoy.client.ui.primary; diff --git a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/renderer/ContactsSearchRenderer.java similarity index 95% rename from src/main/java/envoy/client/ui/ContactsSearchRenderer.java rename to src/main/java/envoy/client/ui/renderer/ContactsSearchRenderer.java index aa96b62..60a0ef2 100644 --- a/src/main/java/envoy/client/ui/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/ContactsSearchRenderer.java @@ -1,4 +1,4 @@ -package envoy.client.ui; +package envoy.client.ui.renderer; import java.awt.Component; import java.awt.Dimension; @@ -8,8 +8,10 @@ import javax.swing.*; import envoy.client.data.Settings; import envoy.client.event.SendEvent; +import envoy.client.ui.Color; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; +import envoy.client.ui.primary.PrimaryButton; import envoy.data.User; import envoy.event.ContactOperationEvent; import envoy.event.EventBus; diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java similarity index 70% rename from src/main/java/envoy/client/ui/MessageListRenderer.java rename to src/main/java/envoy/client/ui/renderer/MessageListRenderer.java index 6b70e1b..047f12c 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java @@ -1,15 +1,21 @@ -package envoy.client.ui; +package envoy.client.ui.renderer; -import java.awt.BorderLayout; import java.awt.Font; +import java.awt.image.BufferedImage; +import java.io.IOException; import java.text.SimpleDateFormat; +import java.util.EnumMap; +import javax.imageio.ImageIO; import javax.swing.*; import envoy.client.data.Settings; +import envoy.client.ui.Color; +import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; import envoy.data.Message; +import envoy.data.Message.MessageStatus; /** * Defines how a message is displayed.
@@ -25,12 +31,23 @@ import envoy.data.Message; */ public class MessageListRenderer implements ComponentListCellRenderer { + private static final EnumMap statusIcons = new EnumMap<>(MessageStatus.class); + + static { + for (MessageStatus ms : MessageStatus.values()) + try { + statusIcons.put(ms, ImageIO.read(MessageListRenderer.class.getResourceAsStream(ms.toString().toLowerCase() + "_icon.png"))); + } catch (IOException e) { + e.printStackTrace(); + } + } + private JTextArea messageTextArea; @Override public JPanel getListCellComponent(ComponentList list, Message value, boolean isSelected) { final JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); // Panel background @@ -47,7 +64,17 @@ public class MessageListRenderer implements ComponentListCellRenderer { // Set the date color to be the value of DateColorChat dateLabel.setForeground(theme.getDateColor()); - panel.add(dateLabel, BorderLayout.NORTH); + panel.add(dateLabel); + + if (value.isForwarded()) try { + var forwardLabel = new JLabel("Forwarded", new ImageIcon(ClassLoader.getSystemResourceAsStream(null).readAllBytes()), + SwingConstants.CENTER); + forwardLabel.setBackground(panel.getBackground()); + forwardLabel.setForeground(Color.lightGray); + panel.add(forwardLabel); + } catch (IOException e) { + e.printStackTrace(); + } // The JTextArea that displays the text content of a message and its status messageTextArea = new JTextArea(text + System.getProperty("line.separator")); @@ -58,7 +85,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { messageTextArea.setBackground(panel.getBackground()); messageTextArea.setEditable(false); - panel.add(messageTextArea, BorderLayout.CENTER); + panel.add(messageTextArea); JLabel statusLabel = new JLabel(state); statusLabel.setFont(new Font("Arial", Font.BOLD, 14)); @@ -83,7 +110,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { statusLabel.setForeground(statusColor); statusLabel.setBackground(panel.getBackground()); - panel.add(statusLabel, BorderLayout.SOUTH); + panel.add(statusLabel); // Define some space to the messages below panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(), BorderFactory.createEtchedBorder())); diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/renderer/UserListRenderer.java similarity index 98% rename from src/main/java/envoy/client/ui/UserListRenderer.java rename to src/main/java/envoy/client/ui/renderer/UserListRenderer.java index 2bdefca..7f6bc0c 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/UserListRenderer.java @@ -1,4 +1,4 @@ -package envoy.client.ui; +package envoy.client.ui.renderer; import java.awt.Component; import java.awt.Dimension; diff --git a/src/main/java/envoy/client/ui/renderer/package-info.java b/src/main/java/envoy/client/ui/renderer/package-info.java new file mode 100644 index 0000000..68748ef --- /dev/null +++ b/src/main/java/envoy/client/ui/renderer/package-info.java @@ -0,0 +1,14 @@ +/** + * This package contains all Envoy-specific renderers for lists that store an + * arbitrary number of JComponents.
+ *
+ * Project: envoy-client
+ * File: package-info.java
+ * Created: 14 Mar 2020
+ * + * @author Leon Hofmeister + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.1-beta + */ +package envoy.client.ui.renderer; diff --git a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java index e30adc9..4fdab10 100644 --- a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java +++ b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java @@ -1,228 +1,228 @@ -package envoy.client.ui.settings; - -import java.awt.*; -import java.util.function.Consumer; - -import javax.swing.JDialog; -import javax.swing.JPanel; -import javax.swing.JTextPane; - -import envoy.client.data.Settings; -import envoy.client.ui.PrimaryButton; -import envoy.client.ui.PrimaryTextArea; -import envoy.client.ui.Theme; - -/** - * Displays window where you can choose a name for the new {@link Theme}. - *
- * Project: envoy-client
- * File: NewThemeScreen.java
- * Created: 26 Dec 2019
- * - * @author Maximilian Käfer - * @since Envoy v0.3-alpha - */ -public class NewThemeScreen extends JDialog { - - private final JPanel standardPanel = new JPanel(); - private final JPanel secondaryPanel = new JPanel(); - private JTextPane text = new JTextPane(); - private PrimaryTextArea nameEnterTextArea = new PrimaryTextArea(4); - private PrimaryButton confirmButton = new PrimaryButton("Confirm"); - - private JTextPane errorText = new JTextPane(); - private PrimaryButton otherName = new PrimaryButton("Other Name"); - private PrimaryButton overwrite = new PrimaryButton("Overwrite"); - - private final Consumer newThemeAction, modifyThemeAction; - - private static final long serialVersionUID = 2369985550946300976L; - - /** - * Creates a window, where you can choose a name for a new {@link Theme}.
- * There are two versions of this Window. The first one is responsible for - * choosing the name, the second one appears, if the name already exists. - * - * @param parent the dialog is launched with its location relative to - * this {@link SettingsScreen} - * @param newThemeAction is executed when a new theme name is entered - * @param modifyThemeAction is executed when an existing theme name is entered - * and confirmed - * @since Envoy v0.3-alpha - */ - public NewThemeScreen(SettingsScreen parent, Consumer newThemeAction, Consumer modifyThemeAction) { - this.newThemeAction = newThemeAction; - this.modifyThemeAction = modifyThemeAction; - - setLocationRelativeTo(parent); - setTitle("New Theme"); - setModal(true); - - setDimensions(true); - setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - - Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - - getContentPane().setLayout(new BorderLayout()); - standardPanel.setBackground(theme.getBackgroundColor()); - secondaryPanel.setBackground(theme.getBackgroundColor()); - loadStandardContent(theme); - } - - private void setDimensions(boolean isStandard) { - Dimension size = isStandard ? new Dimension(300, 170) : new Dimension(300, 225); - setPreferredSize(size); - setMinimumSize(size); - setMaximumSize(size); - } - - private void loadStandardContent(Theme theme) { - getContentPane().removeAll(); - - // ContentPane - GridBagLayout gbl_contentPanel = new GridBagLayout(); - - gbl_contentPanel.columnWidths = new int[] { 1, 1 }; - gbl_contentPanel.rowHeights = new int[] { 1, 1, 1 }; - gbl_contentPanel.columnWeights = new double[] { 1, 1 }; - gbl_contentPanel.rowWeights = new double[] { 1, 1, 1 }; - - getContentPane().add(standardPanel, BorderLayout.CENTER); - standardPanel.setLayout(gbl_contentPanel); - - // text.setFont(new Font()); - text.setText("Please enter a name for the new Theme"); - text.setAlignmentX(CENTER_ALIGNMENT); - text.setBackground(theme.getCellColor()); - text.setForeground(theme.getUserNameColor()); - text.setEditable(false); - - GridBagConstraints gbc_text = new GridBagConstraints(); - gbc_text.fill = GridBagConstraints.HORIZONTAL; - gbc_text.gridx = 0; - gbc_text.gridy = 0; - gbc_text.gridwidth = 2; - gbc_text.insets = new Insets(5, 5, 5, 5); - - standardPanel.add(text, gbc_text); - - nameEnterTextArea.setBackground(theme.getCellColor()); - nameEnterTextArea.setForeground(theme.getTypingMessageColor()); - nameEnterTextArea.setText(""); - nameEnterTextArea.setEditable(true); - - GridBagConstraints gbc_input = new GridBagConstraints(); - gbc_input.fill = GridBagConstraints.HORIZONTAL; - gbc_input.gridx = 0; - gbc_input.gridy = 1; - gbc_input.gridwidth = 2; - gbc_input.insets = new Insets(5, 5, 5, 5); - - standardPanel.add(nameEnterTextArea, gbc_input); - - confirmButton.setBackground(theme.getInteractableBackgroundColor()); - confirmButton.setForeground(theme.getInteractableForegroundColor()); - - GridBagConstraints gbc_confirmButton = new GridBagConstraints(); - gbc_confirmButton.gridx = 0; - gbc_confirmButton.gridy = 2; - gbc_confirmButton.gridwidth = 2; - gbc_confirmButton.insets = new Insets(5, 5, 5, 5); - - standardPanel.add(confirmButton, gbc_confirmButton); - - confirmButton.addActionListener((evt) -> { - if (!nameEnterTextArea.getText().isEmpty()) if (Settings.getInstance().getThemes().containsKey(nameEnterTextArea.getText())) { - // load other panel - setDimensions(false); - loadSecondaryPage(theme); - } else { - newThemeAction.accept(nameEnterTextArea.getText()); - dispose(); - } - }); - } - - private void loadSecondaryPage(Theme theme) { - // ContentPane - getContentPane().removeAll(); - - GridBagLayout gbl_secondaryPanel = new GridBagLayout(); - - gbl_secondaryPanel.columnWidths = new int[] { 1, 1 }; - gbl_secondaryPanel.rowHeights = new int[] { 1, 1, 1, 1 }; - gbl_secondaryPanel.columnWeights = new double[] { 1, 1 }; - gbl_secondaryPanel.rowWeights = new double[] { 1, 1, 1, 1 }; - - getContentPane().add(secondaryPanel, BorderLayout.CENTER); - secondaryPanel.setLayout(gbl_secondaryPanel); - - // text.setFont(new Font()); - text.setText("Please enter a name for the new Theme"); - text.setAlignmentX(CENTER_ALIGNMENT); - text.setBackground(theme.getCellColor()); - text.setForeground(theme.getUserNameColor()); - text.setEditable(false); - - GridBagConstraints gbc_text = new GridBagConstraints(); - gbc_text.fill = GridBagConstraints.HORIZONTAL; - gbc_text.gridx = 0; - gbc_text.gridy = 0; - gbc_text.gridwidth = 2; - gbc_text.insets = new Insets(5, 5, 5, 5); - - secondaryPanel.add(text, gbc_text); - - nameEnterTextArea.setBackground(theme.getCellColor()); - nameEnterTextArea.setForeground(theme.getTypingMessageColor()); - nameEnterTextArea.setEditable(false); - - GridBagConstraints gbc_input = new GridBagConstraints(); - gbc_input.fill = GridBagConstraints.HORIZONTAL; - gbc_input.gridx = 0; - gbc_input.gridy = 1; - gbc_input.gridwidth = 2; - gbc_input.insets = new Insets(5, 5, 5, 5); - - secondaryPanel.add(nameEnterTextArea, gbc_input); - - errorText.setText("The name does already exist. Choose another one or overwrite the old theme."); - errorText.setAlignmentX(CENTER_ALIGNMENT); - errorText.setBackground(theme.getCellColor()); - errorText.setForeground(theme.getUserNameColor()); - errorText.setEditable(false); - - GridBagConstraints gbc_errorText = new GridBagConstraints(); - gbc_errorText.fill = GridBagConstraints.HORIZONTAL; - gbc_errorText.gridx = 0; - gbc_errorText.gridy = 2; - gbc_errorText.gridwidth = 2; - gbc_errorText.insets = new Insets(5, 5, 5, 5); - - secondaryPanel.add(errorText, gbc_errorText); - - otherName.setBackground(theme.getInteractableBackgroundColor()); - otherName.setForeground(theme.getInteractableForegroundColor()); - - GridBagConstraints gbc_otherName = new GridBagConstraints(); - gbc_otherName.gridx = 0; - gbc_otherName.gridy = 3; - gbc_otherName.insets = new Insets(5, 5, 5, 5); - - secondaryPanel.add(otherName, gbc_otherName); - - overwrite.setBackground(theme.getInteractableBackgroundColor()); - overwrite.setForeground(theme.getInteractableForegroundColor()); - - GridBagConstraints gbc_overwrite = new GridBagConstraints(); - gbc_overwrite.gridx = 1; - gbc_overwrite.gridy = 3; - gbc_overwrite.insets = new Insets(5, 5, 5, 5); - - secondaryPanel.add(overwrite, gbc_overwrite); - - otherName.addActionListener((evt) -> { setDimensions(true); loadStandardContent(theme); }); - - overwrite.addActionListener((evt) -> { modifyThemeAction.accept(nameEnterTextArea.getText()); dispose(); }); - } -} +package envoy.client.ui.settings; + +import java.awt.*; +import java.util.function.Consumer; + +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JTextPane; + +import envoy.client.data.Settings; +import envoy.client.ui.Theme; +import envoy.client.ui.primary.PrimaryButton; +import envoy.client.ui.primary.PrimaryTextArea; + +/** + * Displays window where you can choose a name for the new {@link Theme}. + *
+ * Project: envoy-client
+ * File: NewThemeScreen.java
+ * Created: 26 Dec 2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.3-alpha + */ +public class NewThemeScreen extends JDialog { + + private final JPanel standardPanel = new JPanel(); + private final JPanel secondaryPanel = new JPanel(); + private JTextPane text = new JTextPane(); + private PrimaryTextArea nameEnterTextArea = new PrimaryTextArea(4); + private PrimaryButton confirmButton = new PrimaryButton("Confirm"); + + private JTextPane errorText = new JTextPane(); + private PrimaryButton otherName = new PrimaryButton("Other Name"); + private PrimaryButton overwrite = new PrimaryButton("Overwrite"); + + private final Consumer newThemeAction, modifyThemeAction; + + private static final long serialVersionUID = 2369985550946300976L; + + /** + * Creates a window, where you can choose a name for a new {@link Theme}.
+ * There are two versions of this Window. The first one is responsible for + * choosing the name, the second one appears, if the name already exists. + * + * @param parent the dialog is launched with its location relative to + * this {@link SettingsScreen} + * @param newThemeAction is executed when a new theme name is entered + * @param modifyThemeAction is executed when an existing theme name is entered + * and confirmed + * @since Envoy v0.3-alpha + */ + public NewThemeScreen(SettingsScreen parent, Consumer newThemeAction, Consumer modifyThemeAction) { + this.newThemeAction = newThemeAction; + this.modifyThemeAction = modifyThemeAction; + + setLocationRelativeTo(parent); + setTitle("New Theme"); + setModal(true); + + setDimensions(true); + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + + Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + + getContentPane().setLayout(new BorderLayout()); + standardPanel.setBackground(theme.getBackgroundColor()); + secondaryPanel.setBackground(theme.getBackgroundColor()); + loadStandardContent(theme); + } + + private void setDimensions(boolean isStandard) { + Dimension size = isStandard ? new Dimension(300, 170) : new Dimension(300, 225); + setPreferredSize(size); + setMinimumSize(size); + setMaximumSize(size); + } + + private void loadStandardContent(Theme theme) { + getContentPane().removeAll(); + + // ContentPane + GridBagLayout gbl_contentPanel = new GridBagLayout(); + + gbl_contentPanel.columnWidths = new int[] { 1, 1 }; + gbl_contentPanel.rowHeights = new int[] { 1, 1, 1 }; + gbl_contentPanel.columnWeights = new double[] { 1, 1 }; + gbl_contentPanel.rowWeights = new double[] { 1, 1, 1 }; + + getContentPane().add(standardPanel, BorderLayout.CENTER); + standardPanel.setLayout(gbl_contentPanel); + + // text.setFont(new Font()); + text.setText("Please enter a name for the new Theme"); + text.setAlignmentX(CENTER_ALIGNMENT); + text.setBackground(theme.getCellColor()); + text.setForeground(theme.getUserNameColor()); + text.setEditable(false); + + GridBagConstraints gbc_text = new GridBagConstraints(); + gbc_text.fill = GridBagConstraints.HORIZONTAL; + gbc_text.gridx = 0; + gbc_text.gridy = 0; + gbc_text.gridwidth = 2; + gbc_text.insets = new Insets(5, 5, 5, 5); + + standardPanel.add(text, gbc_text); + + nameEnterTextArea.setBackground(theme.getCellColor()); + nameEnterTextArea.setForeground(theme.getTypingMessageColor()); + nameEnterTextArea.setText(""); + nameEnterTextArea.setEditable(true); + + GridBagConstraints gbc_input = new GridBagConstraints(); + gbc_input.fill = GridBagConstraints.HORIZONTAL; + gbc_input.gridx = 0; + gbc_input.gridy = 1; + gbc_input.gridwidth = 2; + gbc_input.insets = new Insets(5, 5, 5, 5); + + standardPanel.add(nameEnterTextArea, gbc_input); + + confirmButton.setBackground(theme.getInteractableBackgroundColor()); + confirmButton.setForeground(theme.getInteractableForegroundColor()); + + GridBagConstraints gbc_confirmButton = new GridBagConstraints(); + gbc_confirmButton.gridx = 0; + gbc_confirmButton.gridy = 2; + gbc_confirmButton.gridwidth = 2; + gbc_confirmButton.insets = new Insets(5, 5, 5, 5); + + standardPanel.add(confirmButton, gbc_confirmButton); + + confirmButton.addActionListener((evt) -> { + if (!nameEnterTextArea.getText().isEmpty()) if (Settings.getInstance().getThemes().containsKey(nameEnterTextArea.getText())) { + // load other panel + setDimensions(false); + loadSecondaryPage(theme); + } else { + newThemeAction.accept(nameEnterTextArea.getText()); + dispose(); + } + }); + } + + private void loadSecondaryPage(Theme theme) { + // ContentPane + getContentPane().removeAll(); + + GridBagLayout gbl_secondaryPanel = new GridBagLayout(); + + gbl_secondaryPanel.columnWidths = new int[] { 1, 1 }; + gbl_secondaryPanel.rowHeights = new int[] { 1, 1, 1, 1 }; + gbl_secondaryPanel.columnWeights = new double[] { 1, 1 }; + gbl_secondaryPanel.rowWeights = new double[] { 1, 1, 1, 1 }; + + getContentPane().add(secondaryPanel, BorderLayout.CENTER); + secondaryPanel.setLayout(gbl_secondaryPanel); + + // text.setFont(new Font()); + text.setText("Please enter a name for the new Theme"); + text.setAlignmentX(CENTER_ALIGNMENT); + text.setBackground(theme.getCellColor()); + text.setForeground(theme.getUserNameColor()); + text.setEditable(false); + + GridBagConstraints gbc_text = new GridBagConstraints(); + gbc_text.fill = GridBagConstraints.HORIZONTAL; + gbc_text.gridx = 0; + gbc_text.gridy = 0; + gbc_text.gridwidth = 2; + gbc_text.insets = new Insets(5, 5, 5, 5); + + secondaryPanel.add(text, gbc_text); + + nameEnterTextArea.setBackground(theme.getCellColor()); + nameEnterTextArea.setForeground(theme.getTypingMessageColor()); + nameEnterTextArea.setEditable(false); + + GridBagConstraints gbc_input = new GridBagConstraints(); + gbc_input.fill = GridBagConstraints.HORIZONTAL; + gbc_input.gridx = 0; + gbc_input.gridy = 1; + gbc_input.gridwidth = 2; + gbc_input.insets = new Insets(5, 5, 5, 5); + + secondaryPanel.add(nameEnterTextArea, gbc_input); + + errorText.setText("The name does already exist. Choose another one or overwrite the old theme."); + errorText.setAlignmentX(CENTER_ALIGNMENT); + errorText.setBackground(theme.getCellColor()); + errorText.setForeground(theme.getUserNameColor()); + errorText.setEditable(false); + + GridBagConstraints gbc_errorText = new GridBagConstraints(); + gbc_errorText.fill = GridBagConstraints.HORIZONTAL; + gbc_errorText.gridx = 0; + gbc_errorText.gridy = 2; + gbc_errorText.gridwidth = 2; + gbc_errorText.insets = new Insets(5, 5, 5, 5); + + secondaryPanel.add(errorText, gbc_errorText); + + otherName.setBackground(theme.getInteractableBackgroundColor()); + otherName.setForeground(theme.getInteractableForegroundColor()); + + GridBagConstraints gbc_otherName = new GridBagConstraints(); + gbc_otherName.gridx = 0; + gbc_otherName.gridy = 3; + gbc_otherName.insets = new Insets(5, 5, 5, 5); + + secondaryPanel.add(otherName, gbc_otherName); + + overwrite.setBackground(theme.getInteractableBackgroundColor()); + overwrite.setForeground(theme.getInteractableForegroundColor()); + + GridBagConstraints gbc_overwrite = new GridBagConstraints(); + gbc_overwrite.gridx = 1; + gbc_overwrite.gridy = 3; + gbc_overwrite.insets = new Insets(5, 5, 5, 5); + + secondaryPanel.add(overwrite, gbc_overwrite); + + otherName.addActionListener((evt) -> { setDimensions(true); loadStandardContent(theme); }); + + overwrite.addActionListener((evt) -> { modifyThemeAction.accept(nameEnterTextArea.getText()); dispose(); }); + } +} diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 56e8cf4..e1ae290 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -11,8 +11,8 @@ import javax.swing.*; import envoy.client.data.Settings; import envoy.client.event.ThemeChangeEvent; -import envoy.client.ui.PrimaryButton; import envoy.client.ui.Theme; +import envoy.client.ui.primary.PrimaryButton; import envoy.event.EventBus; import envoy.util.EnvoyLog; From 819f0ec4f24a6bcdcb4f004f59a0d8c8e82b743c Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 14 Mar 2020 22:44:03 +0100 Subject: [PATCH 261/474] Implemented method to forward a message --- src/main/java/envoy/client/ui/ChatWindow.java | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 2db2d3d..e95de1c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -501,28 +501,52 @@ public class ChatWindow extends JFrame { scrollForPossibleContacts.applyTheme(theme); } + /** + * Sends a new message to the server based on the text entered in the textArea. + * + * @since Envoy v0.1-beta + */ private void postMessage() { if (userList.isSelectionEmpty()) { JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); return; } - if (!messageEnterTextArea.getText().isEmpty()) try { - checkMessageTextLength(); - // Create message - final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator()) - .setText(messageEnterTextArea.getText()) - .build(); + if (!messageEnterTextArea.getText().isEmpty()) checkMessageTextLength(); + // Create message + final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator()) + .setText(messageEnterTextArea.getText()) + .build(); + sendMessage(message); + // Clear text field + messageEnterTextArea.setText(""); + } + /** + * Forwards a message. + * + * @param msg the message to forward + * @param recipient the new recipient of the message + * @since Envoy v0.1-beta + */ + private void forwardMessage(Message msg, User recipient) { + sendMessage(new MessageBuilder(msg, recipient.getId(), localDb.getIdGenerator()).build()); + } + + /** + * Sends a {@link Message} to the server. + * + * @param message the message to send + * @since Envoy v0.1-beta + */ + private void sendMessage(final Message message) { + try { // Send message writeProxy.writeMessage(message); // Add message to PersistentLocalDb and update UI currentChat.appendMessage(message); - // Clear text field - messageEnterTextArea.setText(""); - // Update UI revalidate(); repaint(); From 432a58330b552b31b43f146159962455ceb45efb Mon Sep 17 00:00:00 2001 From: delvh Date: Sun, 15 Mar 2020 18:55:07 +0100 Subject: [PATCH 262/474] Added multiple selection capability to the component list --- .../envoy/client/ui/list/ComponentList.java | 67 ++++++++++++++++--- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 9b5b749..372f33b 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -3,6 +3,8 @@ package envoy.client.ui.list; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.util.ArrayList; +import java.util.List; import javax.swing.*; @@ -23,8 +25,9 @@ public class ComponentList extends JPanel { private ComponentListModel model; private ComponentListCellRenderer renderer; + private boolean multipleSelectionEnabled = false; - private int currentSelection = -1; + private List currentSelections = new ArrayList<>(); private static final long serialVersionUID = 1759644503942876737L; @@ -137,27 +140,38 @@ public class ComponentList extends JPanel { * @since Envoy v0.1-beta */ private void componentSelected(int index) { - if (index == currentSelection) { + // removing selection of element at index + if (currentSelections.contains(index)) { // Clear selection - update(currentSelection, false); - currentSelection = -1; + updateSelection(index, false); + currentSelections.remove(Integer.valueOf(index)); } else { - // Remove old selection - if (currentSelection >= 0) update(currentSelection, false); + // Remove old selection if multipleSelection is disabled + if (!multipleSelectionEnabled && currentSelections.size() > 0) clearSelections(); // Assign new selection - currentSelection = index; + currentSelections.add(index); // Update current selection - update(currentSelection, true); + updateSelection(index, true); } revalidate(); repaint(); } + /** + * Clears all currently active selections. + * + * @since Envoy v0.1-beta + */ + private void clearSelections() { + currentSelections.forEach(index2 -> updateSelection(index2, false)); + currentSelections.clear(); + } + /** * Replaces a list element with a newly rendered instance of its contents. * @@ -165,8 +179,43 @@ public class ComponentList extends JPanel { * @param isSelected the selection state passed to the {@link ListCellRenderer} * @since Envoy v0.1-beta */ - private void update(int index, boolean isSelected) { + private void updateSelection(int index, boolean isSelected) { remove(index); add(model.get(index), index, isSelected); } + + /** + * @return the selected elements or null if none is selected + * @since Envoy v0.1-beta + */ + public List getSelected() { + List selected = new ArrayList<>(); + currentSelections.forEach(index -> selected.add(model.get(index))); + return selected; + } + + /** + * @return the multipleSelectionEnabled + * @since Envoy v0.1-beta + */ + public boolean isMultipleSelectionEnabled() { return multipleSelectionEnabled; } + + /** + * Enables the selection of multiple elements. + * + * @see ComponentList#disableMultipleSelection + * @since Envoy v0.1-beta + */ + public void enableMultipleSelection() { this.multipleSelectionEnabled = true; } + + /** + * Allows only one element to be selected. True by default. + * + * @see ComponentList#enableMultipleSelection + * @since Envoy v0.1-beta + */ + public void disableMultipleSelection() { + this.multipleSelectionEnabled = false; + clearSelections(); + } } From 1fb4ddaa479e29b3b5391806b9e876fe73ab1fcb Mon Sep 17 00:00:00 2001 From: delvh Date: Sun, 15 Mar 2020 19:11:02 +0100 Subject: [PATCH 263/474] implemented UserComponentListRenderer --- src/main/java/envoy/client/ui/ChatWindow.java | 1 + .../renderer/UserComponentListRenderer.java | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index e95de1c..8e7dc55 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -70,6 +70,7 @@ public class ChatWindow extends JFrame { private JTextPane textPane = new JTextPane(); private PrimaryButton postButton = new PrimaryButton("Post"); private PrimaryButton settingsButton = new PrimaryButton("Settings"); + private JPopupMenu contextMenu; // Contacts Header private JPanel contactsHeader = new JPanel(); diff --git a/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java b/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java new file mode 100644 index 0000000..f762eab --- /dev/null +++ b/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java @@ -0,0 +1,78 @@ +package envoy.client.ui.renderer; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.io.Serializable; + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import envoy.client.data.Settings; +import envoy.client.ui.Theme; +import envoy.client.ui.list.ComponentList; +import envoy.client.ui.list.ComponentListCellRenderer; +import envoy.data.User; +import envoy.data.User.UserStatus; + +/** + * Project: envoy-client
+ * File: UserComponentListRenderer.java
+ * Created: 15 Mar 2020
+ * + * @author Leon Hofmeister + * @since Envoy v0.1-beta + */ +public class UserComponentListRenderer implements ComponentListCellRenderer, Serializable { + + private static final long serialVersionUID = -2379244319112111284L; + + /** + * @since Envoy v0.1-beta + */ + public UserComponentListRenderer() {} + + @Override + public JComponent getListCellComponent(ComponentList list, User value, boolean isSelected) { + final JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + + // Panel background + panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); + panel.setOpaque(true); + + panel.setPreferredSize(new Dimension(100, 35)); + + // TODO add profile picture support in BorderLayout.West + + JLabel username = new JLabel(value.getName()); + username.setForeground(theme.getUserNameColor()); + panel.add(username, BorderLayout.CENTER); + + final UserStatus status = value.getStatus(); + JLabel statusLabel = new JLabel(status.toString()); + java.awt.Color foreground; + switch (status) { + case OFFLINE: + foreground = java.awt.Color.LIGHT_GRAY; + break; + case AWAY: + foreground = java.awt.Color.YELLOW; + break; + case BUSY: + foreground = java.awt.Color.BLUE; + break; + case ONLINE: + foreground = java.awt.Color.GREEN; + break; + default: + foreground = java.awt.Color.LIGHT_GRAY; + break; + } + statusLabel.setForeground(foreground); + panel.add(statusLabel, BorderLayout.NORTH); + return panel; + } + +} From 98b82d74d09b1fa79fe35fa9d1f91bb309405944 Mon Sep 17 00:00:00 2001 From: delvh Date: Mon, 16 Mar 2020 11:21:41 +0100 Subject: [PATCH 264/474] fixed minor inconveniences --- .../java/envoy/client/ui/list/ComponentList.java | 13 +++++++++++++ .../ui/renderer/UserComponentListRenderer.java | 5 ----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 372f33b..ed74b61 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -194,12 +194,25 @@ public class ComponentList extends JPanel { return selected; } + /** + * @return the model + * @since Envoy v0.1-beta + */ + public ComponentListModel getModel() { return model; } + /** * @return the multipleSelectionEnabled * @since Envoy v0.1-beta */ public boolean isMultipleSelectionEnabled() { return multipleSelectionEnabled; } + /** + * @param multipleSelectionEnabled if true, multiple elements can be selected in + * the component list + * @since Envoy v0.1-beta + */ + public void setMultipleSelectionEnabled(boolean multipleSelectionEnabled) { this.multipleSelectionEnabled = multipleSelectionEnabled; } + /** * Enables the selection of multiple elements. * diff --git a/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java b/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java index f762eab..e86214b 100644 --- a/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java @@ -27,11 +27,6 @@ public class UserComponentListRenderer implements ComponentListCellRenderer list, User value, boolean isSelected) { final JPanel panel = new JPanel(); From 6873c136c30dc8653f7b760b9bb0ad5fbc9ed99d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 16 Mar 2020 14:30:14 +0100 Subject: [PATCH 265/474] Added IconUtil utility class --- src/main/java/envoy/client/ui/IconUtil.java | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/main/java/envoy/client/ui/IconUtil.java diff --git a/src/main/java/envoy/client/ui/IconUtil.java b/src/main/java/envoy/client/ui/IconUtil.java new file mode 100644 index 0000000..457a977 --- /dev/null +++ b/src/main/java/envoy/client/ui/IconUtil.java @@ -0,0 +1,31 @@ +package envoy.client.ui; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.EnumMap; +import java.util.EnumSet; + +import javax.imageio.ImageIO; + +/** + * Project: envoy-client + * File: IconUtil.java + * Created: 16.03.2020 + * + * @author Kai S. K. Engelbart + * @since Envoy v0.1-beta + */ +public class IconUtil { + + private IconUtil() {} + + public BufferedImage load(String path) throws IOException { return ImageIO.read(IconUtil.class.getResourceAsStream(path)); } + + public > EnumMap loadByEnum(Class enumClass) throws IOException { + var icons = new EnumMap(enumClass); + var path = "/icons/" + enumClass.getSimpleName().toLowerCase() + "/"; + for (var e : EnumSet.allOf(enumClass)) + icons.put(e, load(path + e.toString().toLowerCase() + ".png")); + return icons; + } +} From 561f16f261da52c07b62e7d0b2d5526cf68e01d0 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Mon, 16 Mar 2020 19:08:26 +0100 Subject: [PATCH 266/474] Message displaying Implemented message status icons and revised message displaying (unfinished) --- src/main/java/envoy/client/ui/IconUtil.java | 13 +- .../ui/renderer/MessageListRenderer.java | 140 ++++++++++-------- .../resources/icons/messagestatus/read.png | Bin 0 -> 30078 bytes .../icons/messagestatus/received.png | Bin 0 -> 30067 bytes .../resources/icons/messagestatus/sent.png | Bin 0 -> 26174 bytes .../resources/icons/messagestatus/waiting.png | Bin 0 -> 26922 bytes 6 files changed, 87 insertions(+), 66 deletions(-) create mode 100644 src/main/resources/icons/messagestatus/read.png create mode 100644 src/main/resources/icons/messagestatus/received.png create mode 100644 src/main/resources/icons/messagestatus/sent.png create mode 100644 src/main/resources/icons/messagestatus/waiting.png diff --git a/src/main/java/envoy/client/ui/IconUtil.java b/src/main/java/envoy/client/ui/IconUtil.java index 457a977..47588ab 100644 --- a/src/main/java/envoy/client/ui/IconUtil.java +++ b/src/main/java/envoy/client/ui/IconUtil.java @@ -1,11 +1,12 @@ package envoy.client.ui; -import java.awt.image.BufferedImage; +import java.awt.Image; import java.io.IOException; import java.util.EnumMap; import java.util.EnumSet; import javax.imageio.ImageIO; +import javax.swing.ImageIcon; /** * Project: envoy-client @@ -19,13 +20,15 @@ public class IconUtil { private IconUtil() {} - public BufferedImage load(String path) throws IOException { return ImageIO.read(IconUtil.class.getResourceAsStream(path)); } + public static ImageIcon load(String path, int size) throws IOException { + return new ImageIcon(ImageIO.read(IconUtil.class.getResourceAsStream(path)).getScaledInstance(size, size, Image.SCALE_SMOOTH)); + } - public > EnumMap loadByEnum(Class enumClass) throws IOException { - var icons = new EnumMap(enumClass); + public static > EnumMap loadByEnum(Class enumClass, int size) throws IOException { + var icons = new EnumMap(enumClass); var path = "/icons/" + enumClass.getSimpleName().toLowerCase() + "/"; for (var e : EnumSet.allOf(enumClass)) - icons.put(e, load(path + e.toString().toLowerCase() + ".png")); + icons.put(e, load(path + e.toString().toLowerCase() + ".png", size)); return icons; } } diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java index 047f12c..b537c56 100644 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java @@ -1,16 +1,15 @@ package envoy.client.ui.renderer; -import java.awt.Font; -import java.awt.image.BufferedImage; +import java.awt.*; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.EnumMap; -import javax.imageio.ImageIO; import javax.swing.*; import envoy.client.data.Settings; import envoy.client.ui.Color; +import envoy.client.ui.IconUtil; import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; @@ -31,90 +30,109 @@ import envoy.data.Message.MessageStatus; */ public class MessageListRenderer implements ComponentListCellRenderer { - private static final EnumMap statusIcons = new EnumMap<>(MessageStatus.class); + private static EnumMap statusIcons; static { - for (MessageStatus ms : MessageStatus.values()) - try { - statusIcons.put(ms, ImageIO.read(MessageListRenderer.class.getResourceAsStream(ms.toString().toLowerCase() + "_icon.png"))); - } catch (IOException e) { - e.printStackTrace(); - } + try { + statusIcons = IconUtil.loadByEnum(MessageStatus.class, 16); + } catch (IOException e) { + e.printStackTrace(); + } } - private JTextArea messageTextArea; @Override - public JPanel getListCellComponent(ComponentList list, Message value, boolean isSelected) { - final JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + public JPanel getListCellComponent(ComponentList list, Message message, boolean isSelected) { final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - // Panel background + // panel + final JPanel panel = new JPanel(); + + GridBagLayout gbl_panel = new GridBagLayout(); + gbl_panel.columnWidths = new int[] { 1, 1 }; + gbl_panel.rowHeights = new int[] { 1, 1 }; + gbl_panel.columnWeights = new double[] { 1, 1 }; + gbl_panel.rowWeights = new double[] { 1, 1 }; + + panel.setLayout(gbl_panel); panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); // TODO: Handle message attachments - final String state = value.getStatus().toString(); - final String date = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(value.getCreationDate()); - final String text = value.getText(); + // content variables + final String status = message.getStatus().toString(); + final String date = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(message.getCreationDate()); + final String text = message.getText(); - // The Label that displays the creation date of a message - JLabel dateLabel = new JLabel(date); - // Set the date color to be the value of DateColorChat + // date Label - The Label that displays the creation date of a message + JLabel dateLabel = new JLabel(); + dateLabel.setText(date); dateLabel.setForeground(theme.getDateColor()); + dateLabel.setAlignmentX(1f); + dateLabel.setFont(new Font("Arial", Font.PLAIN, 12)); + dateLabel.setPreferredSize(dateLabel.getPreferredSize()); - panel.add(dateLabel); + GridBagConstraints gbc_dateLabel = new GridBagConstraints(); + gbc_dateLabel.fill = GridBagConstraints.BOTH; + gbc_dateLabel.gridx = 0; + gbc_dateLabel.gridy = 0; + panel.add(dateLabel, gbc_dateLabel); - if (value.isForwarded()) try { + + // Message area - The JTextArea that displays the text content of a message. + var messageTextArea = new JTextArea(text); + messageTextArea.setLineWrap(true); + messageTextArea.setWrapStyleWord(true); + messageTextArea.setForeground(theme.getMessageTextColor()); + messageTextArea.setAlignmentX(0.5f); + messageTextArea.setBackground(Color.red); + messageTextArea.setEditable(false); + messageTextArea.setFont(new Font("Arial", Font.PLAIN, 14)); + // messageTextArea.setPreferredSize(messageTextArea.getPreferredSize()); + + GridBagConstraints gbc_messageTextArea = new GridBagConstraints(); + gbc_messageTextArea.fill = GridBagConstraints.HORIZONTAL; + gbc_messageTextArea.gridx = 0; + gbc_messageTextArea.gridy = 1; + panel.add(messageTextArea, gbc_messageTextArea); + + + // status Label - displays the status of the message + JLabel statusLabel = new JLabel(statusIcons.get(message.getStatus())); + + GridBagConstraints gbc_statusLabel = new GridBagConstraints(); + gbc_statusLabel.fill = GridBagConstraints.BOTH; + gbc_statusLabel.gridx = 1; + gbc_statusLabel.gridy = 1; + panel.add(statusLabel, gbc_statusLabel); + + // Forwarding + if (message.isForwarded()) try { var forwardLabel = new JLabel("Forwarded", new ImageIcon(ClassLoader.getSystemResourceAsStream(null).readAllBytes()), SwingConstants.CENTER); forwardLabel.setBackground(panel.getBackground()); forwardLabel.setForeground(Color.lightGray); - panel.add(forwardLabel); + + GridBagConstraints gbc_forwardLabel = new GridBagConstraints(); + gbc_forwardLabel.fill = GridBagConstraints.BOTH; + gbc_forwardLabel.gridx = 1; + gbc_forwardLabel.gridy = 0; + panel.add(forwardLabel, gbc_forwardLabel); } catch (IOException e) { e.printStackTrace(); } - // The JTextArea that displays the text content of a message and its status - messageTextArea = new JTextArea(text + System.getProperty("line.separator")); - messageTextArea.setLineWrap(true); - messageTextArea.setWrapStyleWord(true); - messageTextArea.setAlignmentX(0.5f); - messageTextArea.setForeground(theme.getMessageTextColor()); - messageTextArea.setBackground(panel.getBackground()); - messageTextArea.setEditable(false); - - panel.add(messageTextArea); - - JLabel statusLabel = new JLabel(state); - statusLabel.setFont(new Font("Arial", Font.BOLD, 14)); - Color statusColor; - switch (value.getStatus()) { - case WAITING: - statusColor = Color.gray; - break; - case SENT: - statusColor = Color.blue; - break; - case RECEIVED: - statusColor = Color.yellow; - break; - case READ: - statusColor = Color.green; - break; - default: - statusColor = theme.getMessageTextColor(); - break; - } - statusLabel.setForeground(statusColor); - statusLabel.setBackground(panel.getBackground()); - - panel.add(statusLabel); - + int padding = (int) (list.getWidth() * 0.35); // Define some space to the messages below - panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(), BorderFactory.createEtchedBorder())); + panel.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder(0, 0, 0, padding), + BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(), BorderFactory.createEtchedBorder()))); + var size = new Dimension(list.getWidth(), (int) panel.getPreferredSize().getHeight()); + + // panel.setPreferredSize(panel.getPreferredSize()); + panel.setMaximumSize(size); + // System.out.println(panel.getMaximumSize()); return panel; } } diff --git a/src/main/resources/icons/messagestatus/read.png b/src/main/resources/icons/messagestatus/read.png new file mode 100644 index 0000000000000000000000000000000000000000..d81f23c4d382048139d443ccd8db4190b25703c8 GIT binary patch literal 30078 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/messagestatus/received.png b/src/main/resources/icons/messagestatus/received.png new file mode 100644 index 0000000000000000000000000000000000000000..3da92824bcd8fdd61186aceac12541fc4988f1f8 GIT binary patch literal 30067 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

3A|UQiZi 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/messagestatus/waiting.png b/src/main/resources/icons/messagestatus/waiting.png new file mode 100644 index 0000000000000000000000000000000000000000..e767b28c3aa70ec3d4e7825d3bdf809deab43490 GIT binary patch literal 26922 zcmeIbc|4Tw_c(0sW->?yAyh_+A|zQ#xT$EfBqbCoQT9k=y+@0BOM3`0rA1Mc?Aw%z zvQ63dDPd$SV-LS;#w_OZ{XMVe`Tq0$y`JZJ|IzC`@B6;)>pIuju5-?H&T-Y;)L4*T zil2vvM{xJ99Tq%1i>UN}*u~(9NmA`k@E<;}UDiH4JV%V^|4_^BZa3iJ!Sn3iVPNTR z*WcC@)tdDN1NW-T&8bfBDUH&gnXlkEuCR&bBC>DCqpyvrxBqrU=%cYXJdE(5pnre- zi-i9!C&1?kXFCZ<~w#YHuC(;3O%lG2y0e?yO40=R4VDkAv#4<4rMM;T1- z_Yjf;>_*rPh0UxvTq1Hx1y9tn=Xq-8a2dhrZLf==v!VG;*gx&tdS8(;Q5<iJ#7m*~f#E7~a)bs5nsSx1 z!kv=CU&}t7c~t~#4o0CK7Q%P#?s7;+5WVHKUg#HCZ0EtPPfQu?KYRc_l`VzsSH=^E z+Uzsrh7%FkLyaLHgc&q?Y$m|Ps1Spuwa;ixM`F-_BI8_L7-BRz|bSXfAGUy5e^<=OhG>lg$39c*Jk7+NKs&TrK%0Q?uN&WA53WN(HDKo z38WwtD!Ayi0*-4Zzo7R4qf1}tAB17EfopkLqPU7|*XMk~bhaUkfoZ4L@~|-*B8L0& zl9z#3m>7Yiw?C=r-f{qj6Q8^GM?r??%d_G(&u?ZJy!F_E%aO+u?R|VC2p#B)-U4Av zX&f#BFHhpM0iVcZd#@#EL1DQ&4VVf`TOOY*K51S14>sL(8vD0!Qu}Cofsd zhwZ+A7u?RAd-)oCvQXIOeUbp`eJRVf?u9odu5~>!k1B+;9AyxEEouKBz-WJ0J@>i| zrsk_pXH5+RX9@_;CoGn#_R_pe6f&F?{gS{!NQ^2zwOVWJVh{MZr&9L}0dXkeX_Mn) zl3oal{UwAC{BQ#7>O}3Tw|ii1`?W*4tht@h7irG%x+jZ(aC9_^iUY7CD7sNhN~G_C z&F#@cuS)6up{%IwSzqmNlVG@fHw-AzPM?gt5A?E;Er8# zch4M#Vf}qw?=4a9wq>gSTFvBhM*x>(u=z(<6lx~(mQonz;s~XCT_kg1+#392UXAVR zW%#jFapT>ncLk0u%S@QaJgkCGR`n!6dVr3~H!PsA^Uu$%XMv1U!Y7wzJ@q{X1@w(I z#1?qjrP#k%%Utxa0JgVxbTPU<#i8NLf@sgGUG)CUfG0s70cj7;{xH(ZPpk6#?oE7Ux|qKzqJIAz*a z5f_0ZG~9WqBvO&>k@lIz%gq4!?lv>j9T=K%ZlL}??V+~N4Axfr<-wx$Uq?rT$qnNU z)BNa>0b92)7QFQU-o7!R2L*`U-5Q5ber!)Ynh6jB^P*%6w@3F>?}rmTTgUj`pKqy; z(`LRUK0$7_zZuxBpiC6%+T7@ede^#@g(4hv13uYraJDd4fI9xSbtW9~^4QH}V6gDS zpPjq1`CkG4x2kO&c?Dh`Tkvu{{;{o~GvNM=b=#kTi+{t7ye0n}|6R66eYBRXlv(W?nuHb07 zNeq)aVFw~Y)Wi8?JVetfrM3oceLv}TtW%UV_gNh7o6gzEzbi1b5hwQ{Tvba}`v(@6 zq2;mIUQzQ1q4h)wPs)KVfgZEnflJvKQ~($}kZoUm5Ds;(o#KC2;5%)Sz*?3fi!zvz zr4E;3sow={tP{M7EIKmS6X)?^d)v0oo-2a#G=~2JN&a^5uF&>vy;q?C3oSzz;i~OY z50@}mg@*uib3l34oaZ+vprgI`ey#)a1Y|%}CXB1~3HWWf7MeQn?R&LwRf+WDZCszG zWeHFVr)CD-F8M^T@COdwSIEtTmbkC?_^3%cBO(>zC0t{?RR#V|d>jj|oL=j9|7#?m z(-je~>sMXEkIM^a7w=oVRMHL>I{o3FO@A$H9}eEP!u++!Q|!^BuQsudbiQmVc@1To z<#XEx7cp{L?!Dr2)ucbltu9bVlUtqX9dHnm&OucsEtzj=7vtmhWDlME4NdKRG@~-S z*Qq$+P|PiRd9l35M)c{ll_*Di4^@oHq2p7G);V35B|49tv^f}ZbzhRkuokL#!-hqS zJq{lr<(9j|tf#bU9Pn#vgr>GmmnQZ{f9U+#qEA-6%#w_a<|J!3{L_cC3X~059fmma zcwcY6`X7OZyOR`5YgCb|IhW<>CuSB@b;{jV-|a`$sgiYai$%zC%^S0^(sM^T9vEkT zA8I}7!!VULqnxweUax&#djF+qn%zM~VzG$gY==ATqx6K=q~>_|JKgIHo(Nh^S>b#> zUfAopPSU-=mk7YO?Y$K_T|ez_J34`h5(5IIJ)$TkNpg$*Ta$qsxD)@cz>dEC>_mO60>Th1?!cuu3Djsq2c}0HGDDCRp-D`#JAGNBjZ%c=}6E-uVWY^KYHW&9I>CL~pm$?;aq1sIGF#eco zb~JhedMz#ne>1&!Urdy&8Md**%t5)x61Hze@^55+Zx>4qERM|b7_u~_SP?!1x6U4q z6lt`=pQ&!L(s6Yf8%qrdvW!IRlFVcdoxY>oPP)_8a@Z^^Hy%!hFU_=zYT2(eJ^q64|WMI`K^Lr zjK{QWe_zvHN?QLP%kf)CSNq%(M0Jzg>Lv|079C?ugy=z9UIKNxjNv_Od(0{NoP>6JB?|4Q9{Pb5Y*ePmX% zL@9V*V1Q{jnig+|?fG7qW1A2;^olsmS1UsG^3P1Gv$^wP?Z)lI5<9IDqQMG8s_^#s#>4&G5KpL2>t4s&ZYc#xg z!B?@2nj=v~3kqU+)(in`m#Mr!ZBEZB#R+RL{YmwrQl zDj1c!UL;4^A+5k%3s^z@1b zedC#8=T)8S(Jlf(9XH+fWCkV&%qxEUUecsuicH#z--ccH$T4$+qBOPZ(MGS!RA1`` z+%cbBmmMy=ZoPwQXp3f`^XDh2r=W67|Fd%2;Ws?f(|aGaNKBw-G{0w}+~9`Rgo5(L zw8vS_OxvUl6JPkp3R$9FY^-OH==rysPkaobiQb@w^lMDit7wH2)1Rq46!jrI#*+Atas~)V9U5zKj<44HxMeD}v9B*UY_|DSnV9B1*=r@dub(eb(7-cKbcY;7y~XRB z?4mE)+n0w*?|@}Ir<`^OjH7-E+(`dw5BmtP2Hrw4T2@a;+_>laX{;;lb%|soT!d8W z78@(BVcMVt3d5Z%6qeb@i2*)dUY^YeMSClq=dFZ-B zQVcrq*kS39n9bQNBkLcmc3;=#J&W@?1W+?Y4~4@pZjJ9M_e-%rzlo@K;CGd50DgeN zTT)ySU$VsIxBC}tj+l&O*c){^J`4;V_9G8X7Us5utymIpOgnCbv5ePlQo@{CT;asG z+uoum=mNUG`U2i_N#{68V_PEd5Cg|mq~F065!;)vD(`byPD1)EME$!_rJJT0-GuW? zcopg2GZ-t)go+Z6WPIO}_SI^7_)lyy5>h!(c~qQ&FN-K?L{t|{@)}Y9(cJxISI-RH zTzfyslW}W%qrb6>RKz?};M1d#j33P*{JlMYF*F~$_md`RU$a}hj3cCOutp>z>YdFA z{Jo`Mj?P1`mWZZ*y{xfg3)2oIIG~(MfpasUkD80il#X~8N0j#0^2p3>C;2F$pzWBy zt0rP<>~zmQm%PS9cn6IQy(995kK}*XxNAnXm(E?iizMW0u71~$XK}OUonU*8F7iOOiaHs;FvJtmLoETx7PHS}7)8k9ixH-3WU^c@LOS!<0xw z{prqIzz2WkyF*vg)Rk?#QPfbfGitx)bj!jYBnApl6&jK-z9RkIU78hfhzHA2!1=GI zR7~DJMa68YD~*Sy$WNToZ$X-0ZpD6LIWTmyt*K^e7Y;`@JNqs!LG-YeYNkOu`m7F< zN(kvR%9&i_80~rUW&1NxvXIJp0V=*0DR;ZJ2q(z$aq)mbtZ5=GPvRU?v)!PnCr^Gp zwT3i5Sikwia_w;104o8OUwo5*C$Q*Id;bbp%Ij*R7tbSEmP3lZjMa`?dMs$mmDEw4 zTgdG3&xbdvhCaP~#9`5j_os04stp{+1gI)`k($2bp6;ouazy=%?rmM7DCxv5HZ(UC zDXFo|_jUV3$c3M+^WM1o@14|*XQLHC)ca76;#zH9P)9S1~_#VaY0-jO^-zrT8t6$;c+s|clV{zl4WZ>ekS=}{=>M&6ro z`tKE}LmPNJJ-TNt8ymZ)q}X(INI)|Bx3vt(`Bfi>reyk3ro&>UJIA^r1l_aJf3y7s zCjsr6DzU-%&uCh%YdN(T+gP@N8N2~VIEs#U_v>}6--f2yPko&XhqAl61mub`^D{B!3j3(&OCw)~=p_Y3>o4rg47G-EMY zx((^RpDFKFr_HF~Dw|D;tS{&Hsl66Y4DI|i;nZELnCt&q>naGn7_mMzHzhUsnU?3B z%p5}%+LrYEZ7f(>w|MmK+a8w2!al}oFRJd{@vNd=k63MOSZJK7Hab|`#PZR$3TO)e ze{&``dnxrn`-fJ0#Zsem*_A%tVk|I7MNrj;&cK$n`I$?pozaoPY`ihpiKGGI7O`>p z?ZU%P$!}PmABcS3Kr&w6^V&&thll=%T~&(s@kLjYsN^y@AEg6SZnP#zo_F)pam>j= z1@~L@>c&Ps1A#1#lXn8;d@`l;8eERFf3GaRzmsCaLOC5aOI)LFdFB$Tn7G|NsY2mY zdd!rye5#0-6ENzBatENPLC+%zN5V8?6*6^MiVP;cK{7^i1_$DMn=!OAby+$RcF;mO|597orq-FsM?DdR>}QMRJVI9x#8JVeT1q}q zB|S+2HQ9!3>THysTjrIus-~{(ja>wy_jI(-_%(sHfSTBA5?-HHdD;Yj7+5sr;c59o zReO|0Y5L?2k4dKYJ*N@9H@}aT{&7lk?Wv4oiIYPXk}>A?-KNuXCD||Fj)klBb5q*_K`&qicV!&bpoAnk$Rh03#!!rkH%8LR< zpSIdZ8L>z_|Dg+HyO`!;vMZ$_F8}TI$GJ4-`I+aEo}vCXf`rcAS>mRQ7sLF|tzV zy@x%2)LmIPpaXqPA~{wto1fa*((Js$lR8Cf-p8KU1*@IZK&>fL#L#ZV?kxRt!T#-; zFLYm+vD-#Fl6CO3_?+fDcPOAPZ6nRb!)Y%|%;~O?Gg{H<1K=oi<@TZV?PUWE2h`bT zOXFVB{ou5a5KU=Rp;=nxT^1G?--ltcuvD?)yqoFr1y}b{!=%`|!4`;noeOoRwTsog z`5}&)u}NuVhkfSZ@K1lpkbkRyxWPpkC`Yj_^?K-NDLc zD~G|!T(+Wt5>Q=~^Z*oY(i+-I#qv^DKP7wp&R>2l%hzYZNgnc~~u38JpS0jK3T*aTZK zKTNcQ&1Mx1e@G3>E5BB9VeYeCq!kGAIt*KFyp zL0JE^Pw>Z+HJ@U|IiLxl9g(TMN&8^4869Xe8j)Nm!o)=Q_@@n`=TTj%9*bwD$KSawQGMwTDv&ca(I#= ziMmh8@v*7jAWXh7l6U(*wzCWbA;wJVII95Uq~8bI*}pyb-pM4VSbolSq@g$O1Pd-@ zf8wRREf!5rw_3#ts?RH!3z*xRoP%H)H&1OY=;ju6Td0^ z%U5eFQ6adFXyKs#R9IjpcsiI_<8Ue7&u%vziT*=jCh?8lxSG%FV%gBZC`i=v=ONJ;(l z5xCkjnxCye7%P+ffyyuFr3ufp-Rk|YiX)cbcENge{!1v}T&N{C#!bMfB_FA2!hsL$ ztV|r}z3HT_Tn|sJ#)*-wW?j!8oEjLqX4!jpD`#;>{<39h({B{xj4-r@eXp3rWMLx^ zkUDUzE|vBF4BQc80D4l7ePNsY3{les_P$~8sNYV0jlIt~I1a-&MpSfTsrQ5Tvu!#C zH8+c1;iIO^-YamL(LBlpt~Ne>b2FD$M z<8JGEoC68?$b2^ptA10SlfJk*(n6k1K*DNhlaXE0{7o+xt4Z-;bJv6s>c{{#~b+d)Vty97K z{M_ty9-af)2`iS~Td1&sW=@36oa(z!M>{#J$QVITwMU;#;Zk0VyaOsd?|^Gv;LEbE z5l6;K=(Db@ z6`5~9V#NOlfV%#IK{I0tIoqCa5DoS~0@)S8_-^XM+1W8?TFfWzV|^c>Z-(j%E~QIw z0z3063I3>?vt*To1{>Qt~X~ z*~hK4Hvw&RO)r_1TQHBeSOF}xQUdAa7{*{x_%ebdeC0jJMH~=9L={d#8-uwtMH%1$ z^(i7h*F$z*3m1(f0sKZXmK+n3{#>Ip9?J!(Ty`ad&GQ?a2X%9lh=y9RPOYR-IYZ?Gtu)-<#EV{|U4*GjZIL3-cO2U zRu3K9+FpBwK3Dn;5C}3;t-MH|W-&kZ_9C_5+j>GZWsH~iz{`U=Cft7K3*dJi)OqGX z-$sl)rDo*x+d07se|qjR-Hg`-7Q0=wB_j|eib0oN%?VvnIkm;rjP8gKq<}phsrP(7 zh~@@z2R)k(-C?|m05LmezAq^RdjBIf!P~xbkP%Y2sW5D1w_9=Elc^TKUagLso7yq! zI-?tGPe|*S?bp#!mjgF?W+3nDxg_01BJD{)RFj*O* zgMCVwLTS#MkvAhoB1C$kmJM)TRNLV$jz^-c2ojy|d9NgB0Jx<5%s3u=`aV*2coc{- z5zH{?vjPmvHS=o|v)l`>isFY&NY8qsP=sy3@J~}s!C#5O z<3jhAC?`;XkLwH^UIJp(chqp4njIh`asPn%K6S8|b%{wdAn^l`nWE#@(aIPE5*(0( z4mmOQ1s13xAPH0&=jvV~g@O$3kBozf&IkaZ(kR)sNBH3aaBW(UtHAjLyyF2W;!xgv zinua5NTl{rrTlJ$}R7O3^6^{UIBJQHX^-yW0GPre-m*Rgv1!RYz+A6 z3nvH9XKqtauSP<+73H zi|G$5geRs3s^f1(G7>PsXUhTlZj5ebrOYrXld}fYKOFY~DK85lSvVHWKM@<~aNsVJ z8w=#7o3im1&1;2C-z_) zjrYFYed{A2@DD*t?jS@z5UZiD#u?nG`2kS#d+~zEImr!W@0mzX9GC+LI>d;jy%qK% zxz)Ic&g-&?9?-_U^UIUu8{Oz8H z9IPdX4O@&@dz#4sQC~!VOg1GEG8j4A1OaI5i@+%lS+4^yT+By3M@M$@dJ4rl!}G;F zcj^Ep(eZ0&<%rP{+_1<96l)7IIB{fNyc8pTgGf_;qnGke=zz4|Bb*tqW0DRKJh8x7!_D{g!_TkxEbQQ;s1 zB8Z80v3&G}_u+8sN*}&i;e2`x9W#x9UL6@}PK=wdMHqDXbj<(W;NU@_Mz*fb?>jfh zurcfa3#Ns{DbuHH#o;zrf1m8w`ryCXIEKIgy4-d0lbV7RBdSTT2ghk2!=Aw&!Qo(i zqZ2;I4010qq&o=Ir76$ngoDZfT(Cgt&mYIV=abDiW|J9=pXn|A(Qf0dMPD5^%$KLZ zP=;s^{)xa|`yy=8TFl7mi2e8Jcr@Pw42C+Dk90YP*AiA<$aAnejd^j84(toSlyzI5+R-6cr(mv| zEYQ^z70)Pi0hxG+9rFgB5CGi^%QLt041Uh2Z1@GFU^MX5V#f6QC=J7LG@&niT_447 zGptJo9YCu5s8}3*XOdW+3HeUL(CuQeL`WK*Lf>B(?Nch;pw?eSOD(vsq*Lw-f z(i}IS>pW}s9iWH%33|}`bBT6wjE&KRCyMnBXs{|*7}&<)ZvuYp88c$lZZWWlCxhe8 zv)1hZ#}=Ybb_57aw$^{#DH{PMNOFqfPAmEeEXUl!{gU&u%@YQ@860=g8ZDL_y9E#h zZv}#}1Cd|A#+bvv58^FwuqHP>WhwRfSGiy%kaWTk4Y~wI0?HXxYI5J@mjP43CopLf zoi6NYPXWAWxnw=(Qpliq0wnWG-{Xq5!*alm+Mi*p??aA!?Fvig$1vnrw z*8Ro8h5kk9zbO5eOBYDQ|91u7arL|BtXzP9l>kS9(~HvnRRaGif&X79fqw=6|Crzl zd5m>*%%Y>8ap(9gUxz0Oeb~H=%lyRUD1sosJs+8cPc?;y2imR~@&9|v|38vCf#wI< zEj`cQMDfxT6sDK`D(m?>Gf-Xj`x+++6ZjeS7{}}Jqv_j-J?6=bpex%3$EE`Bu%RiC zJ5>ueVFprwmUBkYjsE|U6re-ciBMvi`P{^PDBzHO`^!&4CItEQ3}>7LjTUel7S{62 z`y+C|Z4v(G6WckN|DlCh4NZa2okvy4zyj4t_lVxYJ787iWPdJ~rqP1ZD|81#Q;xp1 zo7;l{RTG6arL_x_6A372)^k6oLKBiD3N3!15igUlu&f6_0AK!ZB<6tRKC`(#f62ex zc|<4>rucw9E69~>hJw~ZN_soQ$p`Y%SWPV$?&r2O6q$!1*r}f<(6l=aN~+`A-!81Q z2RPga{KG_g0Ei18Ucf)q|L}7)_tXEYv6Q}tDXR*~Ix<2c3xC*)1|7Yp#G($EH5rfh zDIEOvqM}Qb)=+qc`(g?g1Dd0lDU9)OuQY4}gT4Vj|06)S@hE`RblWUywyMnkfE>rs zq~h^=9sR7~>cJbo7OV`&dKEqb+mEJoY4m2F=8UJ)A{o39^0nZkNYmBUX58V)hp$2I zDq%8T?!S|}iYHdz)=*if`9Ntth%5f@@?7a-gB^~9hW|u4-k4`hI`Y#ANWWL=Ri!yX z&XAbVVp`q0Qkxz{ZoF(X#cv|sh)cM|wMzsR1ng*(Xt|pij-8)04unBIO7{=lUgk;s z!wCxP6Tc}bzes3>o+fcRkh&<}Z5`Jd6P9>-mho9vb}`2Mq-Q~NL5rG|mg+{{aexCg z2!kDpLAIXRg$iE%>LF(pAX9jI{P(_rj(d+51@K$UdRxeHp~q6<%2I0GnZ(o%E31Us zu?-v`CZSD+Avb1I&Ed2Lbumty9xO__4E;v6HMD9S@qNmDui=UQu_!NLrNppU6ewKe zMDWuy5I3)a{M|DA0@Tv!?me7k=s4d9QbiMu@|_$!ztraha>ZB%L5Rf<)3z|TfPhEI zG_UkD`qt1=Y;|-s@!7+bp4m!VdqzlV1QFCsqves&?IdY+*ZCkELtmPqtcmA3Ftp~G z1Kja;x7FtI#Oc^+d8Mk&3+W1CM=@&UXc{tmPw}0V?VilNuQ@{MAyCGX%@-|%C(=8} zEc^`c_N~y5N0Ydpkp?0A6cciTW|i-T-$MuE;|M7W0QX;uS11&jnkjzPy~h5GeuJ?U z7utCU>p@t3S$(`g;qLO@OM5s|SKz$56CdU|Rd}OxM^mt_%{>cJm%*^~2sjrh68L*( zWY}n6w|g}whjJK{wa%XJ`zaI*%2j91E(|?`T`mV|K}ex;1vxIWqA2+vW-JXbz(JJr z-xTlM@q0_CpY3;-xo2`kw#c@4-MvvusD;tBqfLP&=h~_sa8Py|9Y1gr5zVhIC4tD6gNm)rq(|O_FayBjHVDVCK&-y{m6~oL8V;X%3)3ostQ!q zest^14|uCXK99D-Byx=|M7UZP&gez2}j>_)T4suPEJ%T zDf}8pziwgyG{vXwI^H+wtlq9i9Qq^w@eOytIUCYBSv0UH53|jP6j!Kr-H2mV3~wh% zw%AM@ptwqiM1<~p<`-zGq--w6j^H0gk=kFls;E~i&xj$oSQc})UtOZR9>U`&BA`!ulk2t*HWkRx^inWc- zw*hSl3ZIAIKPeBa>^K}*qb9=UTS5oM@zxoo;|&`C5NBLJ?Bd{z0mK_P-wdEEQ~Ijr7!P9$u*s_$!dGd){CZCZS_QwOUUVRP)#Zw z-QCx;Aki7*1oWI}c^w$#DoHL?5l(74o63fY{-agmlr-5dbi_OKbiA~|F8u}dV1yY= z{H^h!-&DygL28n0WKZZZXF(Rpz(txYKK_Qiz)C$wF>+~IT)kZL6`SmipKP$OxExvX zR-&K(BA*lPISYd5;DS)^Z5}fABTA*|r7tW~>~?M9DCx4}O7`4m#k|BFpCE&mFC8lbWloexr4DVOJ=UBFee_;Gbz-E4U-=*%|dW$3AB6 zFkqAH0y^H8*Puv!U#Zak;;PQnEpKGf&j$K zNg-Y(ERGH#&@cX8xJOab$2sc7s$90XE5(BP`eJ=0|Wra zXwKm%ws$1d!Od$VQg^|5FNUI5z8|cAv7lH8cX%D80cQMl`2>t z=h@FGxoE&RhV`8@9=gjnd+U$bc#_g5-x{==f6XaDHm1D}kgP}LDTJ0wBZ<49sR+!8 z*DEHj(%S@hax-XTPz}ajavP9TxR_6VLH?C){ z<7!aYtoP>}%5IeO_l5d@H~~?A?)!QVNr9^HbB35e$~*sD>omP*5lfMK?Izuyqc=8) zpX_+UM^%WvEz@|%K}%(PQQ)F##=RPYc%asP)a=gDqIcGF!CURm6c;>h)wU%q-eTK0 z!Da(}biD4%OK22mm_ZGbX%{%9Ta4=#XM5EI|lpwZSe6H{mgjEG!CbJAkz#${_+PNg9xer1D(k+!~vDrglM zFuo^ZK%P?B;{J94icjGw6^+Etar?enweo6w6Pls70P)}NEnMZ!f~67@U(=x3xMe23 z7zwHBt4Wy|7Wz=I@vh7)J#Bz_c)D$%1QliFR`vAE1b>_MAl+)Hb_I(6;OOl#=H>{|++0xV7 zwfVZenFk*U)PH}MG&w6?+|G-d$$M~9@3Y6xbj|PueKo*EW{+gync1QS-ca6|gv9(3 zj9cw@L5o#PUFraOP;~HoKyAnNj0*>cg>(#;2)iv4J!7`iJ!8R2pnRuiAXR>gPsdO= z0tVFxyGhY|%6Qf+9F&asoI7+PKBJVj9hT`__gJ5z{YzN$#{S!%Shz_Q##J@sgwiZ~ z`p(RN4lkwFQqQlD#s%A++C8@Z!tyHq%7SiXyZbi){DkMZ%AKeC*98MQ3pTzQ)ziCk zSant3Hr*^$XzFmanQ_MRZC8SS?AN>}dYE1CwgKmL-3|$%+^YJ@d(+fzH8ByLADCO& z^@>t3?Y?ouEs`biIjbrCK|2TT2gX0>(Vo_!`W(?;QD+#k{O^a(zmPVe%Yub*N0f8M zXVT>xAU#s991L)Q*=tR+&Q@tNA8ghoj}Kt z4gcP`ktO+n)5nKGMAUy9B!7(FBBWo#gPM_amJNPAl3dynW3*d}>0we;@G%WGsH%6> zw7qcXr^%XUjqy;d*CTXX4c~@nme<}6)YQw&4e_CgebLBleCEwn$8}#Uk*-^}yOVjm z9Yv!@0v?>}4$g9hrZUEX8mYDdz?g^B$aR7&C+I`&1u?Pu*Bo-mPi)bv|(gBszeF zEVA3v>Lky(3t>QpO`=}gVu{vx(I-tmP3cXV82rBuwCl5Z#-Igg_q#;D+6p^LQP zRo4`&FKe+ow!;4)4hi3`PWx)7v}>(U3q$k_&-_`gS@fACB;+{~xV*J)(&i84irQ6kd<5}$F(nXkM4r2`#wJtYg!SZ(eIe6`T3563iH5y z%C8-0+I4hmj!%!ptdNWfXi&Iwmuh45{VkH1_w&T_j*@=(>~xXs?A&GACKcs=cl$Si)W-?-_Dvp|DXhtm;uQ&-Ty zk=JS#ds9a?3;*oU)jRcy=SupItw+8MLZ7bEro;q7T=a9Wd=Y;Z}D zuEyH9(F5NS=J~vv58E~3=C{1*e42*@hL%?-`b}$~?M}^`^ZL&RtQoYUB!F(i)oCSd zRp&gA+zmG`IwNVh2tS9Nyq3EllO zObG4vCu-gr@;4>jAK22jGVy0?ma!FR);2ZaEw1@DdWVWO-l0<;`6%Bs-j0nYMLh2l9QW+OzKoGh7)xe$iAT7U-aL+`$zJna z{5#^IY1)fJza)0nRXt~PaWE3l_KOtPXitNxjs(8qMFm$EO|2(kG*a%UnD)+$e`2kVNJSSNAHz9FMos6>RTBinr>1@H zcDN(ISZ}vyYsb;2gVAJ_2b+b!9>7u60dj7dhM=mQ(`i`XaIF&PtqgRV(g)o=Gw5wO z(!&wB&{(GOM?B(Fu_f(=l>kWZ)=Kv%{<-+L)Pfj>1L}Lw##6&ypn%jTLB+&8)TVWW z!BPyV4^qL$kK4%7Q@@JiU*4R(U51&LH~QOE;DC}jc0J$OkLueGP^e_3IgfgJ=Jjvy8B_XUq*+O4Fe8uzsppN0Q5}6tH?J{$ix)H zeQU>8%NBYLRdPB(Z9#qiyQS}^0w48r8{Z2PbFNg~ED>B)woA{;&sb{qL_phy$K$`U zn^fm(DES^V5u{<-pIV;S+o;(c=MG4r-<@6=E(U6Bk%Ki7wN{@4*@0`)Q9x+WqB1zlL+}GgdOxGQ zpOGcU@OczK`|>U|Ti^qL_E&QjusP5Kj3NNWv3Ln|88`gvbVHmRr?Jg9&oE#?>kp6+ z9X~!eSCb(@P81(60NMV&^V$A%nDGYiMl-5mu@ssXqN}QQ!k}#zb&u`QUBqmg2J4c4Xc=PzjM5JJ zN!4_$92DK&~ou7=(#+|P?f879%>k1Ay5bXVREUj zbI4jeIavB7dPhKtuOzFL66nfZal*=n<^au5N5=~b%!l%I?yy{`bNtwm2UAr=A~>p* z;p{49d~H(02^OEhcM z4)jbIO%0A=mdagw1q#839T!J3M$i|h&g=M{nE#e|2##r(3JBCk5!yYS<(J}ceW<+~ znf(&T;AQsF2k#;<=m53!hH7!#uZ;1&bMt#4WkB!$TAO*sDd5RH1GSNwSnQ}E^*WQ& zY_M1Uh`Vlbyn?_&))&>fu~$a7`N=0`jDf!|U*0B#!I+ zL-Ior2G#L6d3SA*isu zkq;fkhaEdvyL3J#{u>J0Mi<=SXapYLk6W&YuMbzL&txzmNdgLMeP%!`M&P01?OJ#* zTlj6q(?58|Mo-D&zu2aJzKQk#J8iLCwPxd9IJLU@Sqnp#1)3Y}Qu!ivDK tq?Qvv{r3q=SFumO|3g14u|bO}EE@Ky81BmgfBcAN_fFFtuM8c+{ul4$Y<>U$ literal 0 HcmV?d00001 From 42feefdbd5411d738dbe63a8e1291f800cdbea0f Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 16 Mar 2020 21:49:02 +0100 Subject: [PATCH 267/474] Working on line wrapping and message height (borders currently broken) --- .../envoy/client/ui/list/ComponentList.java | 1 - .../ui/renderer/MessageListRenderer.java | 59 ++++++++----------- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index ed74b61..0bb8acf 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -53,7 +53,6 @@ public class ComponentList extends JPanel { */ public ComponentList(ComponentListModel model, ComponentListCellRenderer renderer) { this(renderer); - this.model = model; setModel(model); } diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java index b537c56..911a419 100644 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java @@ -10,7 +10,6 @@ import javax.swing.*; import envoy.client.data.Settings; import envoy.client.ui.Color; import envoy.client.ui.IconUtil; -import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; import envoy.data.Message; @@ -40,13 +39,14 @@ public class MessageListRenderer implements ComponentListCellRenderer { } } + // TODO: Handle message attachments @Override public JPanel getListCellComponent(ComponentList list, Message message, boolean isSelected) { - final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + final var theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - // panel - final JPanel panel = new JPanel(); + // Panel + final var panel = new JPanel(); GridBagLayout gbl_panel = new GridBagLayout(); gbl_panel.columnWidths = new int[] { 1, 1 }; @@ -57,30 +57,21 @@ public class MessageListRenderer implements ComponentListCellRenderer { panel.setLayout(gbl_panel); panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); - // TODO: Handle message attachments - - // content variables - final String status = message.getStatus().toString(); - final String date = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(message.getCreationDate()); - final String text = message.getText(); - - // date Label - The Label that displays the creation date of a message - JLabel dateLabel = new JLabel(); - dateLabel.setText(date); + // Date Label - The Label that displays the creation date of a message + var dateLabel = new JLabel(new SimpleDateFormat("dd.MM.yyyy HH:mm").format(message.getCreationDate())); dateLabel.setForeground(theme.getDateColor()); dateLabel.setAlignmentX(1f); dateLabel.setFont(new Font("Arial", Font.PLAIN, 12)); dateLabel.setPreferredSize(dateLabel.getPreferredSize()); - GridBagConstraints gbc_dateLabel = new GridBagConstraints(); + var gbc_dateLabel = new GridBagConstraints(); gbc_dateLabel.fill = GridBagConstraints.BOTH; gbc_dateLabel.gridx = 0; gbc_dateLabel.gridy = 0; panel.add(dateLabel, gbc_dateLabel); - // Message area - The JTextArea that displays the text content of a message. - var messageTextArea = new JTextArea(text); + var messageTextArea = new JTextArea(message.getText()); messageTextArea.setLineWrap(true); messageTextArea.setWrapStyleWord(true); messageTextArea.setForeground(theme.getMessageTextColor()); @@ -88,51 +79,49 @@ public class MessageListRenderer implements ComponentListCellRenderer { messageTextArea.setBackground(Color.red); messageTextArea.setEditable(false); messageTextArea.setFont(new Font("Arial", Font.PLAIN, 14)); - // messageTextArea.setPreferredSize(messageTextArea.getPreferredSize()); + messageTextArea.setSize(list.getWidth() - 1, 200); - GridBagConstraints gbc_messageTextArea = new GridBagConstraints(); + var gbc_messageTextArea = new GridBagConstraints(); gbc_messageTextArea.fill = GridBagConstraints.HORIZONTAL; gbc_messageTextArea.gridx = 0; gbc_messageTextArea.gridy = 1; panel.add(messageTextArea, gbc_messageTextArea); + // Status Label - displays the status of the message + var statusLabel = new JLabel(statusIcons.get(message.getStatus())); - // status Label - displays the status of the message - JLabel statusLabel = new JLabel(statusIcons.get(message.getStatus())); - - GridBagConstraints gbc_statusLabel = new GridBagConstraints(); + var gbc_statusLabel = new GridBagConstraints(); gbc_statusLabel.fill = GridBagConstraints.BOTH; gbc_statusLabel.gridx = 1; gbc_statusLabel.gridy = 1; panel.add(statusLabel, gbc_statusLabel); // Forwarding - if (message.isForwarded()) try { - var forwardLabel = new JLabel("Forwarded", new ImageIcon(ClassLoader.getSystemResourceAsStream(null).readAllBytes()), - SwingConstants.CENTER); + if (message.isForwarded()) { + // TODO: icon + var forwardLabel = new JLabel("Forwarded", null, SwingConstants.CENTER); forwardLabel.setBackground(panel.getBackground()); forwardLabel.setForeground(Color.lightGray); - - GridBagConstraints gbc_forwardLabel = new GridBagConstraints(); + + var gbc_forwardLabel = new GridBagConstraints(); gbc_forwardLabel.fill = GridBagConstraints.BOTH; gbc_forwardLabel.gridx = 1; gbc_forwardLabel.gridy = 0; panel.add(forwardLabel, gbc_forwardLabel); - } catch (IOException e) { - e.printStackTrace(); } int padding = (int) (list.getWidth() * 0.35); + // Define some space to the messages below - panel.setBorder(BorderFactory.createCompoundBorder( - BorderFactory.createEmptyBorder(0, 0, 0, padding), + panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 0, padding), BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(), BorderFactory.createEtchedBorder()))); - var size = new Dimension(list.getWidth(), (int) panel.getPreferredSize().getHeight()); + var size = new Dimension(list.getWidth() - 50, panel.getPreferredSize().height); - // panel.setPreferredSize(panel.getPreferredSize()); + panel.setPreferredSize(size); + panel.setMinimumSize(size); panel.setMaximumSize(size); - // System.out.println(panel.getMaximumSize()); + return panel; } } From 6a2cb38bd2f11ad83426fbd0f99f8162d695a43d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 17 Mar 2020 09:37:19 +0100 Subject: [PATCH 268/474] Working on message scaling --- src/main/java/envoy/client/ui/ChatWindow.java | 8 ++++++- .../ui/renderer/MessageListRenderer.java | 24 +++++++++++-------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 8e7dc55..5e87a00 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -131,7 +131,13 @@ public class ChatWindow extends JFrame { // updates list elements when list is resized @Override - public void componentResized(ComponentEvent e) { messageList.synchronizeModel(); } + public void componentResized(ComponentEvent e) { + messageList.synchronizeModel(); + var prefSize = e.getComponent().getPreferredSize(); + messageList.setMinimumSize(new Dimension(prefSize.width, 0)); + messageList.setMaximumSize(new Dimension(prefSize.width, Integer.MAX_VALUE)); + messageList.setPreferredSize(new Dimension(prefSize.width, messageList.getPreferredSize().height)); + } }); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java index 911a419..f6b6596 100644 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java @@ -30,10 +30,12 @@ import envoy.data.Message.MessageStatus; public class MessageListRenderer implements ComponentListCellRenderer { private static EnumMap statusIcons; + private static ImageIcon forwardIcon; static { try { statusIcons = IconUtil.loadByEnum(MessageStatus.class, 16); + // forwardIcon = IconUtil.load("icons/forward.png", 16); } catch (IOException e) { e.printStackTrace(); } @@ -46,7 +48,8 @@ public class MessageListRenderer implements ComponentListCellRenderer { final var theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); // Panel - final var panel = new JPanel(); + final var panel = new JPanel(); + final int padding = (int) (list.getWidth() * 0.35); GridBagLayout gbl_panel = new GridBagLayout(); gbl_panel.columnWidths = new int[] { 1, 1 }; @@ -76,10 +79,14 @@ public class MessageListRenderer implements ComponentListCellRenderer { messageTextArea.setWrapStyleWord(true); messageTextArea.setForeground(theme.getMessageTextColor()); messageTextArea.setAlignmentX(0.5f); - messageTextArea.setBackground(Color.red); + messageTextArea.setBackground(theme.getCellColor()); messageTextArea.setEditable(false); - messageTextArea.setFont(new Font("Arial", Font.PLAIN, 14)); - messageTextArea.setSize(list.getWidth() - 1, 200); + var font = new Font("Arial", Font.PLAIN, 14); + messageTextArea.setFont(font); + // var frc = new FontRenderContext(new AffineTransform(), true, true); + // messageTextArea.setSize(Math.min(list.getWidth() - padding, (int) + // font.getStringBounds(message.getText(), frc).getWidth()), 10); + messageTextArea.setSize(list.getWidth() - padding, 10); var gbc_messageTextArea = new GridBagConstraints(); gbc_messageTextArea.fill = GridBagConstraints.HORIZONTAL; @@ -110,13 +117,10 @@ public class MessageListRenderer implements ComponentListCellRenderer { panel.add(forwardLabel, gbc_forwardLabel); } - int padding = (int) (list.getWidth() * 0.35); + // Define an etched border and some space to the messages below + panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 20, padding), BorderFactory.createEtchedBorder())); - // Define some space to the messages below - panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 0, padding), - BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(), BorderFactory.createEtchedBorder()))); - - var size = new Dimension(list.getWidth() - 50, panel.getPreferredSize().height); + var size = new Dimension(list.getWidth(), panel.getPreferredSize().height); panel.setPreferredSize(size); panel.setMinimumSize(size); From ba222deec9b1948a8a2cfff1846ef7e900b69d19 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 17 Mar 2020 10:08:58 +0100 Subject: [PATCH 269/474] Fixed horizontal message placement This commit contains potentially unstable changes to ComponentList. If the ListCellRenderer is not set, the class might behave in an unexpected way. --- src/main/java/envoy/client/ui/ChatWindow.java | 4 +++- .../envoy/client/ui/list/ComponentList.java | 18 ++++++++++++++++-- .../ui/renderer/MessageListRenderer.java | 14 ++++++++++---- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 5e87a00..5be89f1 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -65,7 +65,7 @@ public class ChatWindow extends JFrame { private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); private JList userList = new JList<>(); private DefaultListModel userListModel = new DefaultListModel<>(); - private ComponentList messageList = new ComponentList<>(new MessageListRenderer()); + private ComponentList messageList = new ComponentList<>(); private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); private JTextPane textPane = new JTextPane(); private PrimaryButton postButton = new PrimaryButton("Post"); @@ -614,6 +614,8 @@ public class ChatWindow extends JFrame { this.localDb = localDb; this.writeProxy = writeProxy; + messageList.setRenderer(new MessageListRenderer(client.getSender().getId())); + // Load users and chats new Thread(() -> { localDb.getUsers().values().forEach(user -> { diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 0bb8acf..3d90ea9 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -31,6 +31,8 @@ public class ComponentList extends JPanel { private static final long serialVersionUID = 1759644503942876737L; + public ComponentList() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); } + /** * Creates an instance of {@link ComponentList}. * @@ -39,8 +41,8 @@ public class ComponentList extends JPanel { * @since Envoy v0.3-alpha */ public ComponentList(ComponentListCellRenderer renderer) { - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - this.renderer = renderer; + this(); + setRenderer(renderer); } /** @@ -199,6 +201,18 @@ public class ComponentList extends JPanel { */ public ComponentListModel getModel() { return model; } + /** + * @return the renderer + * @since Envoy v0.1-beta + */ + public ComponentListCellRenderer getRenderer() { return renderer; } + + /** + * @param renderer the renderer to set + * @since Envoy v0.1-beta + */ + public void setRenderer(ComponentListCellRenderer renderer) { this.renderer = renderer; } + /** * @return the multipleSelectionEnabled * @since Envoy v0.1-beta diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java index f6b6596..f3ef692 100644 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java @@ -29,7 +29,7 @@ import envoy.data.Message.MessageStatus; */ public class MessageListRenderer implements ComponentListCellRenderer { - private static EnumMap statusIcons; + private static EnumMap statusIcons; private static ImageIcon forwardIcon; static { @@ -41,6 +41,10 @@ public class MessageListRenderer implements ComponentListCellRenderer { } } + private final long senderId; + + public MessageListRenderer(long senderId) { this.senderId = senderId; } + // TODO: Handle message attachments @Override @@ -86,7 +90,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { // var frc = new FontRenderContext(new AffineTransform(), true, true); // messageTextArea.setSize(Math.min(list.getWidth() - padding, (int) // font.getStringBounds(message.getText(), frc).getWidth()), 10); - messageTextArea.setSize(list.getWidth() - padding, 10); + messageTextArea.setSize(list.getWidth() - padding - 16, 10); var gbc_messageTextArea = new GridBagConstraints(); gbc_messageTextArea.fill = GridBagConstraints.HORIZONTAL; @@ -98,7 +102,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { var statusLabel = new JLabel(statusIcons.get(message.getStatus())); var gbc_statusLabel = new GridBagConstraints(); - gbc_statusLabel.fill = GridBagConstraints.BOTH; + // gbc_statusLabel.fill = GridBagConstraints.BOTH; gbc_statusLabel.gridx = 1; gbc_statusLabel.gridy = 1; panel.add(statusLabel, gbc_statusLabel); @@ -118,7 +122,9 @@ public class MessageListRenderer implements ComponentListCellRenderer { } // Define an etched border and some space to the messages below - panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 20, padding), BorderFactory.createEtchedBorder())); + var ours = senderId == message.getSenderId(); + panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, ours ? padding : 0, 10, ours ? 0 : padding), + BorderFactory.createEtchedBorder())); var size = new Dimension(list.getWidth(), panel.getPreferredSize().height); From 5f2b05dcce0d92711145d6ad63d2b29eaa391c1f Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 17 Mar 2020 11:08:58 +0100 Subject: [PATCH 270/474] Cleanup --- .../client/ui/renderer/MessageListRenderer.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java index f3ef692..7b2b427 100644 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java @@ -35,7 +35,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { static { try { statusIcons = IconUtil.loadByEnum(MessageStatus.class, 16); - // forwardIcon = IconUtil.load("icons/forward.png", 16); + forwardIcon = IconUtil.load("icons/forward.png", 16); } catch (IOException e) { e.printStackTrace(); } @@ -43,6 +43,14 @@ public class MessageListRenderer implements ComponentListCellRenderer { private final long senderId; + /** + * Initializes a message list renderer. Messages with the given sender ID will + * be aligned on the right side, while all other messages will be aligned on + * the left side + * + * @param senderId the sender ID of the messages to align on the right side + * @since Envoy v0.1-beta + */ public MessageListRenderer(long senderId) { this.senderId = senderId; } // TODO: Handle message attachments @@ -87,9 +95,6 @@ public class MessageListRenderer implements ComponentListCellRenderer { messageTextArea.setEditable(false); var font = new Font("Arial", Font.PLAIN, 14); messageTextArea.setFont(font); - // var frc = new FontRenderContext(new AffineTransform(), true, true); - // messageTextArea.setSize(Math.min(list.getWidth() - padding, (int) - // font.getStringBounds(message.getText(), frc).getWidth()), 10); messageTextArea.setSize(list.getWidth() - padding - 16, 10); var gbc_messageTextArea = new GridBagConstraints(); @@ -102,15 +107,13 @@ public class MessageListRenderer implements ComponentListCellRenderer { var statusLabel = new JLabel(statusIcons.get(message.getStatus())); var gbc_statusLabel = new GridBagConstraints(); - // gbc_statusLabel.fill = GridBagConstraints.BOTH; gbc_statusLabel.gridx = 1; gbc_statusLabel.gridy = 1; panel.add(statusLabel, gbc_statusLabel); // Forwarding if (message.isForwarded()) { - // TODO: icon - var forwardLabel = new JLabel("Forwarded", null, SwingConstants.CENTER); + var forwardLabel = new JLabel("Forwarded", forwardIcon, SwingConstants.CENTER); forwardLabel.setBackground(panel.getBackground()); forwardLabel.setForeground(Color.lightGray); From 2de64956e4e510fa1597cb24b4f9e5e316081991 Mon Sep 17 00:00:00 2001 From: DieGurke <55625494+DieGurke@users.noreply.github.com> Date: Tue, 17 Mar 2020 11:20:45 +0100 Subject: [PATCH 271/474] Minimum size of application and added forward and settings icons --- src/main/java/envoy/client/ui/ChatWindow.java | 1 + .../client/ui/renderer/MessageListRenderer.java | 4 ++-- src/main/resources/icons/forward.png | Bin 0 -> 26014 bytes src/main/resources/icons/settings.png | Bin 0 -> 29000 bytes 4 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/icons/forward.png create mode 100644 src/main/resources/icons/settings.png diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 5be89f1..eda61e4 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -103,6 +103,7 @@ public class ChatWindow extends JFrame { public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); + setMinimumSize(new Dimension(400, 300)); setTitle("Envoy"); setLocationRelativeTo(null); setIconImage(Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java index 7b2b427..10bece5 100644 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java @@ -35,7 +35,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { static { try { statusIcons = IconUtil.loadByEnum(MessageStatus.class, 16); - forwardIcon = IconUtil.load("icons/forward.png", 16); + forwardIcon = IconUtil.load("/icons/forward.png", 16); } catch (IOException e) { e.printStackTrace(); } @@ -91,7 +91,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { messageTextArea.setWrapStyleWord(true); messageTextArea.setForeground(theme.getMessageTextColor()); messageTextArea.setAlignmentX(0.5f); - messageTextArea.setBackground(theme.getCellColor()); + messageTextArea.setBackground(Color.RED); messageTextArea.setEditable(false); var font = new Font("Arial", Font.PLAIN, 14); messageTextArea.setFont(font); diff --git a/src/main/resources/icons/forward.png b/src/main/resources/icons/forward.png new file mode 100644 index 0000000000000000000000000000000000000000..9c758540eca22d5761372b724bc589c75d109221 GIT binary patch literal 26014 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/icons/settings.png b/src/main/resources/icons/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..f956615fa7133ced0a93b645706a9a9812a6a574 GIT binary patch literal 29000 zcmeFacTiMY6EDha1{k7b6i|YaqjE?}7(@}t2$I7XQBXhu$uJ`-W;qHbq6z{M70GGL z5eAhcaZr&QBqQnd9t7dL_f_5ds$RWUx4u74ojL5i*Xq@)dv*7(yVtp3VYZ8%MUaJ# zj*fk|;f_6YboAZmKR8DCi|K>fAMh_`Z$o<@Iyxr<^dAgww7wo4ohaSz9eUOQF8!^| zr&?ZLSFm{ZU}51_Yi+@yFVSy}=mIZ%7_&-zoIyNayyq?3>Ce*>RpD41rzoCChe7`P z*t%a> z>lmW6ZNsv4ZHsRG9!V5y-HJ*O=?D_OL(Whe%H9Is!8~-O~6(qI!2d?LXpphaZk4R|NlI3>OT3?e@jH zv{fy=ofJ>Rlso?r{Ij|W?&0S3^-L(KaooyDiP!yI7pYzve%OpmTwLDL2(TG+2;&%? zm^6(Ke@9Y=0Q=cOIN50l$XxH23PyiI`Twm7IgAF<7>4%ytW8HRZ}lj`XYdM3hLx zXyb84|M5BFpS}G%50+Coi3z92y!vxsBKu$J&_Vvo#AOcsmx-vt{8ti}6y*OMb-vCz zJ3Zk#!XItEcsx1r22?JD&sN5>EAIcTLBb>L^mX@n5v&Vtw$Zz?a&GeL>zQBSGrtzj z8Hqk3(jTlnSUavy9{sZQyyS2%+pv9k{mG}B>h!4|m`H!QGkAoQ8gaQwQ|~RiaY#wF z(DkE%4~Shq4UQH5-b47A_qn8?5%*F+Iq40>@GLt+*nITtu09p@!(L|v6(5onC@#$; z$Gr~QF%c%uYglfU^=cjs6>ySwkljeYEAgZlJi=u*U2dOgyq%GGvn90OuCMs4b@(2# z4|>|?Okw7Rth0PPuHdyW3x-Z*Cf2ofga-1HKAkHMYPZr3wjzn)1J?@7+wYG`AQEum zN$juP!9Z$_{WUnV_pRX?nkEub$b;oy*U;NM>}kRdGOw)}DxT&ir6Z;4KN4Rx-%fqq zy`T0TwSb(SN4|F2ylqD9wi36rERZOeSuldz(a5{8HcD!93^(n3D@GUXf7ROfH{s9e&&Y7UzcMVtQ(0MLW3C;USh2RTlQ~3^^N@a+tLw|VnW8jn zV6m56;izgK%2lL9z*l;8#bP~KceF)qY&a#{}8D+TvFC8wXhPaHJN!P1F1_4 zo;PuF=F%}In2^PSKfX)Fv9VgWM}=>1yd8OKNAsFf(|I*&)Sp*^8P#0rl$wTyXGh)0 zi5SEKnBn2%oS%-5WSD;&-DQTKaw4q2~$kUr?e*?IpD z@eRT4wSHl{$kda&6o&jubcM1e%RFp5AH)2QM=VUYlLm#J=xKM{FSmb^AI4MNfGcBO z>*B6NPkB>0l3(qSV>71@lv-Mvloj;5u#0Jt&e)Q#kTN<=?!(Q-V zRM+{P<GhMqESp=FhL z$1#sG8&Y}=+(GmDt>rR62eX@DBEA1F+4{bn$|6!0crrClX9uOe>vesPkG^fU7y&=@ zZ=RwTOJkJR^Ux91*ik1+qHUg8Ls5w==`xa#H)=I{Io`wlO7*yJeh`olbf@>obs~Ep zcd~kqv1k@WB2&>QDVnI)9T=C8Phr<}c~%nV)q61?b~t~ewrUebXk^pdcBj{`L)z<0 z%1~9`${H}(X56kanb6!_nEAm{Cb3TvsJK}a<_c7}a+^*QuLQ<@x+`2bvKzrx@DKN| zcN9w~Jz!?8dq`V{Z*1-&ka01+x2FI&q1KwE)O1_dEsx(zLB>@aPp}}5HjMgvr_0aX z_A82Rcy$A!mm7?!{nH5J{pp7rZJ%l`*uL8;Y_F=LPb8aQC>`Od+7WKqnZG>jBfi_{ z*t?R6F1iQSbKn}In4?EHH+3C^lmf=-h z-&&FX!wkYOuC!UF36q38gTt;VBX?tucLt3E!^gMOeIml%(DhJv$$EaQZ+XVhS&zk; zaHUNgn{Y~aB7f64xhcqzvGaK+yxl2YS0e}8BX@7@LU7ELuR)g{Cs^wd$yy{9iW}u; zVBfyF7}?Ccy=vKxjzIV}*Va%Vyvu?6j=GzNLW6^q0tRVdc%t(_J2A&CbVSI$;p=Xd z$!Y}xo)Vwfs{{;GA~5_u^6<)6LDr|<(ZCWl45jCIt%6td(a?N0!!KXpto*XuS@}Nk znaqCK@2Wf7iMyl9h3^XS%R_t!~pZYmL!{<;h21VO2*e-7pU40}uK?W{zZS;g&OVr7toPOG(!EmTk-&>yBgb?Vy9FjV`CA7a8t6}Zqm6UogKgj&omPfz zP_{fHd+^|af>YafK3of|nzbR1wmdJAQ+{%4(4~12mkC>z!+&Z{0%6RQ$ULO@`|Imt ztv~~^ki<(3^}JLryV(VjNBnTAOehi#pyuy-mrDUE7X@jU)aOE_OsQix+iv(-`ciJ z2%8F3`}{~YqWMLOFZ{#>MCiQvv{#aKZM9THiSW{NWL=~!*^$i>g#hlFd@o_^y7Ho7 z(HEpSXRm=6bq?MAedk8cr>9-`LyUzL5OcTq@Zfu)v5!4`8Li$f@)iS2ZaFA~_inP# zn6Z;inGxB$!l>SF8HjLU4!ALI^md^FEMSFkQ>YG~a-5^^a)g)4z}Az>lhMC(pJe*_x?)dz~8vR$ci+ zE$Y{8gmsAQ8w$005jZsK_s6s6d@D*d4LTRyTXzJXbL(jLRkp5s-!1?0W*bJoq%+r% zoKrN!?-io^BJlfgzS&|>fUcEn3^s^bV29Ct77zn z@^>5<|8CoIpwsf9;ETXJ(yE|R%bO_)1gY!!mt5&6vuX;GSloKt81Jwo(2-F(!5EtF zo!2K+9m|mIyfi6%{E!)hS-_{x(qtfX87_=Tu84g=uMrnJV8U`;fUT6Js4zxM>*LMXN#S^IK!9qI#D%Fox`tymX~ z`hNpef#wNL?IhS=8FpAD?eP*FMOKblct;{+6G5eAk{(nWT2fTg<{XTAF` zgJF_aV5MKtS2QKK78c9?99_Av+Yo;ze(#oD`L_TW>e)u)`}HEqNrhJzCaZ#v*sWkF zjVf^~#?Kidz`|V7_pY@+ikKv2OC#Y)fL|klKE9 zgCy4;i@$ncQ+g5N65O?AV#2qCu z*MfX0`)tupr2&x(a)SMj3T7Xi$T;Y{7@vX=CS50Xl~y!ER^uZK2=JbiGJ}KIq%<{pdj=zXY=% zEOHOIqwj8ZdB@#b<~*WNw&eLJ_0sb(LNyy7UVkbX`8fHROe`JAoI$wcrvgXtOD$tt zalGhNVyL(o|6bY6Nw&MU7>aNZ^iEqaVvs@x;R4Su?BSnWHk))tz&`Qkx?(w`P8?+% zd)cv5zV)8mepz>MJXHk~nW5qFVxCKiH3rn&fjs}K>8;csJf@x%!=zw*22F=>SbgFS zbiP*pBmZA>pwyKd_N2Y+%X;?i_|I*P8TxgAJi%xJn8?(UOV8)`s5{1Uy%i;dzl+*4 zD9GMjJj&`?9$`Iop4TwxGEv{^j0*!oiDIBEzVqu7J0O8A84I&%$hbn?|>4y zu3#)KM1q=hFf@cWx805hi_7HB?aI9F*Ln>B{C58(qW%~D!|Gxd4&;tB-!kL7d6V+{ z{49|HY`^Y+xNcJ}W==XhCw80k_|vY+Z@OxN~q?G!L34XrUzwT)8ojp zn8>8PPqJr>$O&WMgP0|y5<}D72DwVql6D#1vuEefuR!Wa6Rp?z9MU zASU?BG}~5Nh$rLbJKENt<6xprU^!ScW`$q+_bD;-oATpGZOBAw+w`vPHsS`cv#(V( zaH?QN2C%|GO*<1R_61x2#;M||*NLIM+_%;!K>|hTwBOgwn8-vl#E-HklcWInT96@B zKHr{-KI_fkX_2SsJJHqOeBZeui;FHI!7rc{#7fmFV%efwQmQ_pg-@Vm7 zkz?CC#L9CUhAH;cza9Y=&rQ^mJ=_Z?BOSJ&>zm3I3G$g1|K1OY! z%pr4 zd7J9W%p&jpWW~=kGYB6nxKX-~2Qy=TBPo9!>^r|K$Ez~Pyf}&<#R|KB-jPz1jBqHU z>vq7*I5c(hCK!_2Zc59i%$o!5B9_eUeS0_Gt^GG}8fBZ9jqV&`=s$kwL0#iM%uI6! zUCaDUK=1ftmEyU*&udByRq!zgJIOwLl==~wDEiowu6>uNtq5tvbzlmw8BIG$V{6f2C#n8PudeKrE#N755==O5u3 zyB=*yzXl8|28O9a;H=|VJ6^z|K|a=bD(@x2A%Ee8Rgec}#;I>gHQbWy;?MQ*jXq!$ z`mgV&$srs{wogL}Vu>$|3SW*p?j^g}0!muNo!edo!ORz!^9ys)!U0U=%{ONhEv(7= zQjX*{xhoJT9_uTA>T>0_+Y82kC5ZWatnHG%@hC&mTsT(PTAmTfXXy9OAFXRu#RRv3 zhjUeFc-JiVURqifJ@|*M$oTyVoKwc+L%&iBGukM(82ZD}AiRh;rxbvH9}56dqCwC0 ze;I_W#Zw;?SYje?0IswVPmLs&Q?{mw6BaVAC+iphZ#Ej~+;Aa_Nraxs67p6)3VdVM z;?HH$k@O`+AQNP83`60-3OmzkYR;^Y9CzKny%gb)^zRJ0Mn}4aOyE7lV~N_zj{AG# z0Xj>(*DaWi6}H&(s;0##lXV(H8D93c z>#S7~*gL=j-tD3dry64-xmm$v#3Kos+wxm4fr&i;UgI^*Y3qF$FHV-o*fdq9&K>(? zV(^{+oFPu`b|KmX3r8@C(2W#;9{RpMv;=ft*&H!nM6<{lF(Bj#_{Fn|DgJCi%U zm)!9Jqh&+(IhvJ|agB9q->0G&^LnT)X!u~giyql9OK+(21c2&*by=)DqQijH^@t_q zfRjVL2deq!=SAX+AwGpf2|V=-v8$HZZ*o?edg!9+ClI(c)#=xv!BlmQ1@AtN@<@7b zfHTf9Xyu$s4~YT>STW3QJYl8jEFS@Yj=oX8yKhZaOsXf&mnYZjl(CjgE$^;+^i;L#+wvdJ#6pph9= z$h#-=6sbl*&DCfV0dLNGb59O)0MT`Hq^A$zNNK1FiJ&9hMG_)aed_oy$P75wGgYns z(vc8^;{n6=S|HboK}#U@WJ#j{;_}>XLkzqT^W}I;ER+BDVfCkjoF$mA3gGR@P^WKi zQQOHQ%4rCwx-?q~fF-Wv4wWzi*-dzACb8>>{eq(ZsYmK5KnIO6xw>WO!;kJ^)AfK>W`VS=T zZ$Pl(peq|wAE+(Gbr=ZgNt_V{)IzBU#s`_rNV`|~7XfB0&oGgL-;i`tSeo@r8UuKq z%;2lNvV62Q_*A-vqxyIDpuVZTf4pAg+&C0%c5KY@x&^=lF<31}xs-GP1ZxA(lWkfF zIJW5w!lG7hQUeg|Y1V+(jBBKi2D;R5VmJF*39l$z978s|?b*myM~pZ?3n=lH7)sOq zXYQBiNN+$G!6X3gz=vUaExWrH_KOWkC|N7l>|NU~hM$@HQs&_IoB~&NNvn(GJbdiAL#>RW$UC0^P?(B+YGP#~E7% zr6s8tC;1xv0gbgAPWwA9g?c1ckgY;#C<2m$A|Rpi*UX$aNot_5eAJK5fD1RY$Ui%U zYGRe>29{zPaR3)KCMPi>STkVrVug(`mp7-@^TCI-aEWjUf?>zotp`cuNrndB-H0)R zmiMiZf}*01vYj9AZo-SE6GL^5dSgBmv@@~o+^q!bQ@Ri$dY@ReZNIFh`xE=Fx4UDY zOo%_1GFcsdcyeOy&fV;MeZaExziK~ZZp=-!EGUaIEjiSG7sM)^sI7a{``P<~Nha1E zno10_>&I^G&;f=rV1#_n@{YqVDGX)6>}X#M9VroYk5>f5r0Yl+&x3=RDY09UZe1<3 z@!61@KhpB`N}=+f!+8{|RoP`lL<00n#VD^No?wEryz#+gfPrvJK5Vs z+`tqFC)kmF!a?$MaZ_^KH+KLq5cI?MZo|)xuOXNtiL~eu+`wctY32 zG?G-=oIfm0eHs+t^gZ_rut_fhQ=g7QH5|#6p`YI7)p|^2dLY0Lr$C1w5%=a0W=++H zg9?>Yi~236Oi}A2fSDof)I(K=J}73>IIW25&$y^gR-|UT{E}cO(^gv7H}mzE{l0t(G8QCQ*?AxwlS@dP#W1KW05x4f@bsXnfKvmXQO^afX zR0vAV7HiSoiV-T`{(D1~nR5y(qvzf;T*DJuCcG?5AjDHHZ^q+1eisecyJhz8*@Qvb z&e_qbpS*XHD^BeE;Ks~(UL2AW*UxMPlVwd7`|u5o)X|{r8U$^S8`}+AxI1)meiu21 z-=1xmAF0^5o#yXKhjsx(rwU9vg7MPbzF3fVMj-dvnQMk5$b-N(IdUw2L;LX;!Jp)EE zo@Xzl5F?WqMj$kj?mLYNm<@B|0h@OviWo!%^ize``TI>`$1Fq(%lHLItTp(&|JWVp zdMitUT)XN6TW;1_9sLDT|p)2SpZyF`n*U2sv} z_KE)3xt?nF?o^&50pV-P&fW94LsJ*p5TskMSlSszcE@-r+pv~`(Sv|rlCb898mKZD z`fJe!5e{YAUYt+(m#|F+Y@8$OncKMx^g$5zm;mIXE)es%mK8od$R}u;G+E%HR?*=La5R2~gC~Pn*yUKdLTngCE)NkAx|_Em_`;xAIi2Sj}>$e4!ff{~X|CD2p*%pZE=R?G4Cbb&~E^ zxN%ZYq9}0T^fIx)XGy9;(9<36^#|}dcQUeZXLyFy#GN*=h@ZEFg zTECbJ3Z2c`yMo*eP$eMpYkJEnUUUA%Fhj(s4OoRW=ofFL2@CIUH#OazJJs#rYP&E| zMfBub-i1Y(SgP{GAHsNv$fjnf!-ut?w{;Y|NUS)_wK2sqlfM$NUY#S#1=+8FY&!E8 z|8V_1|M?QM0Eb3W5fmCXy_pGVYHruD@AHL9)X?}WIn>INT`+Dh%G(C(^~v_X8sgZy z!(#)wCjxNY5a2Kkq5%%d0d1uEQgB>rN)B=Kd!g4tgZg~s*2$!S3S?|qv%&OYNr`#( zU3%pMLcS4!XLL`yr^(k$KXcHuEe8cnDkZ8MMC(4{k@b`t1B||F>f*zbTQV~6Zz7L2 zWR3#>PVz*mueWkH3>_tTcD=V*xLC^6+oS6;xMB`E(g~7?ic_j)b``NrruJ9o;EiQn zw8fT`SC#Jno`=uP<$i~ALnUIx&C=u{(Q;` zvx^taz>iO7&k_^-I?`j8)Kv5#v7P_YolB1ZAeGimvR&vgI?Iq2=>R|h_^<4Lc3t#7 zzEd-2jJV;%=Jch!-k%MaHB0Izx=g3a-drUjTUo8+Cyh9|_rBJ&GB^aiWCy?Pz32@^nJW?Nkn`o>7tSw zd-r%l76-Gu!0_boO`cK=N;Q@@cYy)iGVFD5?`|-qg{+Wi9A_E?&pH1-P+XxW;J_3^ z;1)=HzbsoCQq+bP%GXjA(w~x#3uFTf(~T>Qo;#OL2Y@DtE?Zq_g<4BICF1$PlHW|O zU7Zq00kux~UiWva+%e&;9{IU_Jl&8H7`l;f#%vuGR7 zo)8PMtCD1pucSe8@azGaU9em-?4ZVkY*4c7)C{g8VpR5^OSe^**O_Y%YPzmvV41D% zEK`_MRZf08390Z+YC$lUv?z7hQgnyH^0{yZj>yQ%J1tkzC0b(&t5G;Hw|cV;fvs=t zc$b+^6PH#vx1?Tyr$&5+PuCJRkG5(tCkpwLf600^=^nV<9)`hH_?S2Tb zlK&_9FuV$;@?nF#_rUUw2!j-g?DMx;J?}7@I^|pK!u~H+;>&Xmdlkv!{dWIJoz-tx z#ls(f!!E{CD>ltyDIXUgOKliUVEIjRFcvp+GqCXX4f7TL6Y!Aq2R2=im`8c|8bs)T zna*Fi0)42IJ$2`!0PZO`zlB#_S0(U7Id=khKuhKKuS$e?!~F+MpF|M)&Lg`_2x)dBQ8^1Rg7@{uQt^D7MPEn^}P~fnd=b@5_v8#t|j7 z4{8EO2XPdna@K5~=3JI*QZN!m4W(2S;(Xx@^fz&)tdJ1^rr?a)pvcYecLuNtc!+y~ z-qenptU4JwK*~DAE&mRU&hdZRpw?VdqXU()<=ucSje|6ezaIP#xp09f25M|ppO2h& zkUMwv>gT}jVV$ZgtNkUDu=IlHzhLk!?Tl8t86_}w$=6<*Q@(65xWP5$Ih$g=>a#D8KDk+SDvo1kG#&7xDM~_$hQINu(0M%V92F4)vAcgkV_eham zAoGf?kn&n)bW#~CC*-Bzrj;8803qWTn@sw$Jrlh`Y~O0k6SJN94A`{DOFQ&dQBq?G z=6tiC_7Z|e<2qggC@C`J-LZ<2^37HLJLjtg%Fx9`d*8ZP5n;a)O@!Mum?wiA-qsk?2T# zND9-~Bi+6Bk2#%|>NROvu?{Os34~{CmyECcoeGr!Y9t;4x)F0*`F)Tbm@RRAx}$cf zoGVSjBD6wIH)+A{YMp-O_%1W`Ki`rXkucHq+eGTP-pbeP$5Vu(npPbSNpCJS48@$~mdI_(^9@kw0tkZxM&N71qkanEK{p{RvMGO(3si{fq4JT{i0fGL$)=kGtBm zB;1b~wo=>`!g-2LY+tGccs2L^miQfvJ6VHK(n6A_ejF^9QS2eS1iazUo5wfA+M4sh3bQ~uh zZ^g2oonNpO+};MWPH%+9lx(h^^;vkfpQjXU5co^lN9M<)@0^^Q!#64V99ic+S@S;X zy5J%kNn9AE4F=I6=jcf5K=RgI%!bl+FQ`X=GKA$3zQdCfa*4~zaYT|DSyhFI9BJ^n z$RRrY_Bc4H$G5s}!V`9opB>)u&TVOGIE!Wu;|p1CGEenFeL7dZ+ z?1*+9(Td;G!(TBh|B(Em0uZCEx9i`u3RC!%^s2xO={khbkkqa!pdSVNA`zO_$e zd~lw{t@dDV?IC>5jTE!LM4+ZSWMzFQ@|6@w<>w70KRp{Ju_G z8fGp4%d+yM01c#dWuNXu!oC&7X|%GJ#TyFTIStzZf!=&A8tCDm_sY$ez(65XGfZP2+^E48jupVP4+@cNkF&(WF z8WYu%j#zby1VOAA+?5lIh+)f$aaUh5~6A2aXfc$0mC;T9~smZ<*kIFMNP(05l*#GH~Sp%FtY*(_YKxikmu` zEb#}ZjN>1km_@sZh~yzScIz21$Udy_&F4Granio7aUip%)c+DW-bM_IZm$BsUz%W8 zD2a|sfb8yJ^rR5=hGM=j+v>>;%v0$B~-=RDy1N=8evaX2SPvXnD%TMM2gTP1Fe1 z9yVMCkilB(PO;N^v;$;@=Q^cAh~({<*v{=O;dfXdx(Qll;Mj?NNb%IJgV#S_@{75WYkG{!q-5*)In!8oO5JFqR#J@6^p+kWz z2^uVUq;Q21fR4Uf1}E}*tnXmT(ZcE|YjX3oKdxXTL%+yk-GCx&zS529|7a1vtweP_ zkqGTe>I}2dGm=gZa;EF@4EA}Tp2Hf3IJpgo+DwUxK^~dD5QwIFM;k1;J&=9yMzarq z_X4za?cWGl2sk*sse&t99nw=&UXS~#vZ@p7KKh-q4P!sPi0LO?CFbpjm-qMk=JXf} z?F}H8Dq=aZZb^Db!^pYOVJ;a+RSQ7o(RfodF_CcY;>Kf}ISBh6SgwUb^(u3t(A7_+ zn=uFvoHWoTagmM`3Tf^A90z8~S{E@xYu@3LY5N})2X9I0sx}}0BbuZMB#h7;#!Lt0 zmtCU+*^#6wU&dX6ha;nF6$7t$8+RqJ5`+an7z#1`Y#Kl~+ z0?!SE5w@iO4y1xlZ#-Mf|2fe0U@MJ$aF^B`SxodE29L|ly@Vfwyuk{8UZfU2HI$+r zvM71m#Cr_y#glKaWF`HuvxEY(n_I>3R9ZPWrw!R$?S%nPfpTPi?k8zf%c16A2x<;s z{Up#F(sK(I3_@WLZb}d;S=`t(d8&j(r|;>m#7N8aKpzg#rRNd1Q zsKYk2iU}x-9WD2o$lE$O5ppxRFB5{s94LsCK{nh+8)06GWz+J-Nx6`0?eNYwAVOCL zqwgi~ES?}7K2UFl?go@q$WvcY4sCJO0C!iHIC!%Gt7VcCI1Qa%@Gwo1%9LHlUAG2< zB!Y@%u_IU`R*l*in(zM)=diFB=g2w!^5L(OcW6cJOCnIIl-Tb#tRt83Ra>3DPM1GdD zx8?4V*Ov^ONxf+NIE=-e{Ub!&6boNi2kxW5a7Y4Z5Zo%lJ(ZB*RL2cfWsIH@A32BV z6KPhOj--i9OlV%s9)X(1HutyE0Ajwbtu-N%c`=dCXljiXG$g#a#_SA2B@Rca0P~Xr zLTaN|({p;hnm3}oiNHrNxm{p#efE;u(4xc#Py@3F3VEB5JBFc8ciHqUry~Q<1_DOd z0qC#%TH0RrVtu*xP}IrR4eZdgtI&QY(rfy>Dh(q)3!MpPU(`WDZW;9>xg#8x7I)2( zLCfob)ht-EL?@x_68 zHb0s>F^4TH>bVv8>MA>0ZdZRJ@SEy9Xp_g#XaR7K6ae1@GvuHkr;JBWK8Ht z1-BLXp@_<@{=L%}iwSIg*??F5QWbm0V;x_ zShAun_jh3AHOJ|L2quz<6_Zf-Wd0KxBaflCo;2RNHd0tztX*PSs~|YeSWc_2pr#Y` ze_H9aOW~7ZiCu@GAkmlz?KAYhY3(yfXNfNk)39eU7DM^Kd|q+$ChEX6=Z!TIAQ)0C z#_2f>TFI_L(=Va;xf%+kOd(l-p}hOOt`CkeKV+T*Eoah^rh0pGR=&%cQ%>7m(*!j@ z*NJnJP_FivBj`jJo+zd z9^$+x%{yANE$M?w-vRi~p?Coe1F%3uD8~EXANF-x0GkqA}!r4S(X#MsyMG*4wGqIChVr?N9;Un$$ z#_38NxkYpLl6^d(nT<=d#srQc8orzBLhkS@f4mK-G9Zr*TrMr0m!Q776jP%I%}xG> z_Sf2lrR7gsAsjrZKU#0mk-j1mpTFME_TNbk3xdSH3RpIk)YJ)Zq4>dt3b;?yf3?Hp z7PQ8e66buj6$^!N=3aB)j)%guU|OLBnF|xyys_WYh=}fF4(uej@+4N&gCUQ6nngGS zr&T_-kkskWCKpl|GVw9&&aVE(wso8NRI_-YCNU-315}L~PkfQxiH3h4hWOI=B_LnzILKq*fOs3QKto=y+P7r#(^1b+ZSNqpVG}soGYb9b^{`Kq~fviQRjnt|6C5 z{~n6zJ-NM=zoI&O7iwGYGA1S;4<=ksiY_*R{Ze}1w+~Lm79Q__imsoI5Jd40hXfw~ z!P5o3gkAlunpeT+MN6hJ7^WEdZqLBosi{loR>t+rq%Y~Pi5 z24Es%z!Mnu!bI{JgVB+Ks$8j{is0?!3jgh`+7BSj^kCDyt62z#93-}nT_@6iK<^r; zF(ijINcZp0Y8t%=m8O5X0BpFt?b5Fwr059S(Uxh;(C=saDn#c#QCkTb7aYKwcLfLF z9#+_H`>T7mnGg&^j6H{EHZy?^fvnRlk+%Y7|bZLBjI*ea|mx`o>UtY6O`U z9rc$#^qHaVm|5RyDv*m=D?mGKYKwk7$3(LHP!S8k3yFLbX1?P7HxnswaATdwJw zKv$y9CMu^2@CN%F*Vq7VeiRj%D5PR!hOR>uENuNQKJW7vplSF%v&PFE#yhmJVSKr% z_I%iE*2ebi*l7b3Sl>q{Yd<}*-cRJ_HEy^|O7Ha^QBEtUn1?dqR|2^?ui!$G1F%Nu zSYVN*it_xk_D~9!chYXa_AWsc{zazD^5e)v{_$GRr%;DkfvZ2%z^d^vQ~gw=4#M$I z=#%=R@|a+Is0_2xCnwl!e3R|Gwx(1vvCNCUP@Z=_* z1+*{%X4I1wxwMgL!2^vhwS3;W>445wL&HJ!@6uo;7&50U!`B0!bN%2A9pPhlu~}8h z2#5N<`xb^LF*CL!bTNrGWSyI8B?V`NYMKoab52CYqE|B9BtBDdwEl^`J! zgoP(MTREh7Ag{^yU}bFl$UPc@@`y*I^JCj!a>z;NvBniiFB30K_hB5 zajrKzZfF2(8+uTEKsdC~d@cC|hAHtomo(u9QQMv8X)~vtC?Usz*n9m8Z21>y=OYh^ z5fl^+$b~9bx60yegIu|~11C-iAQ=q(RvBlV7a*5A2Lmhccu(0I^gYKytH3PUD!>j+ zD(r7P^#~7$q3#-g# zf^=;4$FZPwD3H)t%G3=ygQVuOZnbzN9o}3fZS0sIau(aa z^XzkzmWwDv!Dr;J{3z=F2HZzJZ~Wc99`{O?#^6jA1gpc7%VaME?ZRlCQb;&cGHh2o zIf)qY8A=4pd2_qUHjRKkH_x9tX~!Z3uStyywKwafgKA27TaigUl1|@qzIs3tf*(X- z{hDhqp>qYmHlPIhm{>Ulfi%ioY2e~)^$#d6W8w+_g;h` zcV_nw-`={zXxH)EtHNp9U*DHTvarIrBd?ARy}fnkBC|DLZltxTnu{yrSiqg=jJKE! zr({8Kh^9z#X3-NDQDX%iGOUd%nU~jtimZQsWvGK(hZ-kCSt?zDjz;i{pacF8&R-#F z@4u3fF%Q^7q2Nts4Wa_gdZ@8zT-JV5Afl!23xL8mT%*9ZgO-oE>4RQb(~td7=BHi8 z1{FG(fyuIj1>;-sm!Q6S2YCbMrt_x{t*v1_7gQnql9kFkPB6j z5Zfv5B}eJR(2U~_@zw0LwMI;4EL=Z!H^Q`oD3Bx|9&>KyVRkz?}*V7F2QLh zPB3(R-qd@aam?lf<#@ffPQ#bFC4Ue*!n*eJs9V4jdZ=5RdpW5VC&gjj1M@G&HO5f) zZ5(Lq+5+VwZK_r4s{ce0wCDKsP}&Xg_o@B(_H<{e%ehfR%zYW)he~8IXe&;SU0Y-P zs<>d?i)pB?S}syalOh=A-0FFMm91OOkJY)^+eO+W>(8XXJU-=QuTHa275bpwsR>>$ zjrQ;Tipxa7Z9zSLdGTMril`|4bbu>7y5I^AE?SJZNcCpWhRr^fP;Olq~Ph z=Qhw-u)U@K)&%Ffgrwg~Q8V^F^VHtSBNtvi0$9~9@J#w^?+ubHXP4=LIBv)PkOuH} zAz#WJUAH3}5}umz`uTxJgjbYy!`u#V_&B0%3(HhMrA2^Pfuj~>j;%ZJ$sU;%1Y&W# zklhgAm^AYUyX*fSjlaWCGBDp#!?(08=zst{UV3cobX;dO06?2d^a;S9C%3w<2L9AQ zjnphXq9LmJOVMJveqOO!_?p8iMa?UKaMU-&w4PiJa2J34Z{E#jX*4xI;Tr8wy8`G& z>&h6%JTLSux5(1)pzQ#3KtGrC3gTp0rv~cY_p}XF5yRT6)t9%6#s~60V1E8F68I0y zc#>iE0bz3Beb^|aaN)gL>T;?IgG53-*GvZ;(%vS7UNo^f>GB&Q;Wnv0?tUXQDH)1dm1RQ81mGr# zHMU?QZJ!E;*GJI`r!GQ7YGt<3_s&4#Ru z05Ts`d=ZtPshz+4R0}R5)%`RIEw%IiYIrQ=zGyq54hpYc6Vi#^O`#BV6mBUnf8Z;& zycjAhhKi9;pa}g(Dx0JNPgDli5B9PLMMkSncANe_>|MC5B8`#+jdp|95d+4tn~!t6 znxaq-b%}r22`HbQ4Dv6Fbv-e3yCh+m1L#3b(5QrNVRg8jp^~}F13Jo*p`(m;@hiG@ zcqgc>Z#nj8?@xBP+G2bu1qM$*fL~0501E<;6iWAQR{|^C9I{f&7bh)kF7#sb%^<|W zc`B4Iw5*|8Abn`C?+D7|c&x(LmK=qG*~=uKg3a;YT}q+VoIiFZM^(hPurCwN2%8gO zp;NE}_Ph|9pq3v%MJ#ZFa?`Fns9X=M_uZ>yyUo$`_8&RygbzD6nte)A|5GEsyx$qH zG0^xv`3QnD2#CT;i0VCXQxV!_MtcWtnex_wW?Dy(U}#bK5d#td35@vV=LH~a0PSk? z4a*IhGlVWSG0>)kCW&*SzW?S+HwumMZ|*w!Id)9TK7HvVgNp#X6I6?T`vpg!w@|GB z!-orr9W8s#%Y#M%=HBqrG-$;ICw8!NuGqdOOI~LIFnC4t{cqUvnZt?c&@cb+sbIak zq1W1yn@e1{0bIDD=j;jj?NDgUqi_S1cingWA1TD^!k$-tRPpZ@x$q$_VPy^zx(2*G zPaK4CpkPT{uL@aUaEO&$HbH>&9EI@ygWnDYIPUIjnV6j&3mJ=pd5`+5qNa0`_( zNfITYE1@$MF$@xV5%`%JJ*NxM=h>(|y z9^7pd@5;<3a(FZMd1-2D7nhZ$)t6S&uYy}|+$x1_q532K37rYw>p$0teCFB6X-{1c z7f3~0#V+GoG;8L{vcm(8>}W(2in%t_cRnG<4`nClk$=B~1m-T#FOis$;u<6@Xv5Zo zlvh=4(OD@eCyJr=90JGNH^<-|m?e#ci{_`VKxI(I2 zo)^$RZqiqZH)U|sGjn;L3BkK|ca6Dcw&~Xrhu8-hJfbz` zgz?d4pVBvX9m=l;N%wBK52h8u{Gd&Q17R<3efvA{ zoYVFLnsZw1H*C+B6_}M2`I|z33^lLgdLS15yAJ{dd1ZYjop1>P&)eb5iOXR(f2Di5 z**T^jYbksP6dcYjfwnC>dVBRlk!0=<<{%(!xP!rF!8&Ws2zGD$T5l`5HDwd{G^j(_ zz;NtiLzP+RgXa&AmB%}14+1D^MCwOxOpD1l(3YQ+s%Hhp#1aj-Yxg|gM1LP|w&##k=oJ%R{ux^jeDlhUdKLjEwYcYMN zKTz1`m92}<=2v_90KD3uz%_o1CwH^ggAEmysit3l3%T&a-P&X^5(niV<(vMcz8lS_ z?0g=-+{@;l)QSUM*Q(a(IXB_>X{%(EW6}qeN5+ZkY#zvONlt#f9);a3PF+I< zF-#|6F!qURKp6WYB6FP`9UW&q`u_+3TV9DR(YdA_NttKvE*Y$TR2poJ-be~Jr|yL2 zLDT7W`p5M9Z|ux5MV?``A|n_+XA1Y_*i)NAWuRjfE*0n&CulS!J~f^8@##CU5ahcH zX~k+qgqybH`41%`9^N^HrJa9@OJhN3W0TrF4_Iv|EKq!t6#}UYK#_whCw`T+PD;IX zXmJ}bD~2-{?Pp}f#Eu3Xj2+QF;4zvI>&4ZrNWBvr$`H`zqFy?}?lE%lCgl{AF`+k4 z=_6`C#U46}JdtVNKhtSk-;IVG7WU-P3Hy=+xG_;@rogZGb=}@RK+n+j=L?8h=Y`ut ziifORzPp!apYYp@tYgq}>w5TedTYa%-*FJzs)9U1Gi)8)Z#cT?ZQ+N;=q~%PQxbhN z;1*7d=@KZG zAYrGnS9MOr@u_ouWoVB561p*biHU9p@e3srQ3&lP{)Z z9~Ikg33pt(4rzBeP##^87!H5@-V!<$zA_wpugMdV7#rbM&9*n*imamI=J{wsNVJ{~ z>WDzhA&oYIoV)G1@l;J_et*_4^cK&X(9N5vHE8o)bJ|t2@Ash5h&HkS?sFC+vIeAK zXoI9z=?J}%E4w@)o{3}E(R3`EQu;SR+4|8>nuH_wrZ@qp=70v4kZ8!BAFK9SXiDxV zs}teysDM;es3`U86rIvn+frSDtnq`aHpTaVXK-zp6F;e1D9=>$gRHZyTi1A{SzSyX zOMv8I)4{-2=ft!1v!nUnS+H%aQ@g%pG9hp|ZDX|8mzdw*-uTswM>)t^SAi$Z$gz3a zVjm`)ktH%CA8o!DdEo#3A`;KY6MOO%U)jS{vv9?FT!}j`hEguQ`(^fn4=R+z$i_Yk zKd2e#4$QL(v>tiXpg)(vrQriIQg{FfsVz2X+9`Um$NT_P?E8XT^k zU7Z!rI&BVcLppE`$qa|1wwsgu4^HbX;;1oR5X}NC;W%$hX`fNk0j{S1CD%+Qz0Uz>t#Ky~>Nkrf--!(J#peH2&%+?`N$`i7}*Ld=0>HhE7c zgIh(wg>c0Vz=ol4EU+ae4m|l|s^Ezq{YP(1IjysQLT}0+V?m*yKyMbC|I;>X+n=%R z`8<2}x6^eRm_cFZP=0zI(@nFTIbXlUghE#$WV6g+z6LsnG#uD21n%A|XW|7WF<$5E z;GHfy;wL`6zih#-6VH|B@E{o25I71PEOTh()L^x>#Zj zbn@;Kraljf8E0?03hBiC;<8}>ayIUHAq%i-1CGLbIyZX!kLdB;`H;!xPSKLD^)n8= zWd+UADFa=wQ%Jx2Y_Pa@qo4t(dYl4%}1)ZaaD2pyRo6Gw=X{ zz0RkqcytS@f^BO5UwEhiZenogh*|svJDCr7C~}Mlux%)Qum*V4P2=4CkJ60erY?FN zCwOD$v-MY=Zf2?DsPKzoU(QlyC%yJ_uqHT@0(V$j0ndVp*c-WSU!8&9Q%Hj{glYG; zm$BbHTh~Vb&l}(42tFdeM%Cc8`b)E<*E+Kftl28NR{!f2fe&ZaOiX^J7iO!x_U)O~ zPH$y_ir-JzBp1wW^K*Bmy?Ns7!dI#bfV1zrW!Gg1 zO#elHd=&mRU;5qe|FeY~Uofq{$LIP!y4I3~$H=niRm{^9#$S$Gm6^TRihve!6^sU-wXg2QgO=es2f8ZihwZ(92-Vm z*l!A~226{t09VT(nE-5VE*Ld*G)$o#JW$FQuq5@Tes|e~TLuCwi~|4vU+na6bZF9@ zaP#H7Pgk90t-R-b8ak?J#Uk>hPbL?6P>GT0Arn_sMZ+=p7$dOr!_dgb$hueAJsQbx zz%KcYh9)_=1s`FZIdEQB;OyY|{=`Kwq>KUF&7iknK|6Z}>NdO=0s$ASi?*OtOkBTI^~6B~NC#q>ye`B}dIue9*}|dm zLf7*a>N3VftRi1t{NRC>j(0R4%$F_C+9eJu7h^;NF0Aj`3Eu_)DQ0UN931~MtOBk+ z09pXt0<*T}{K-&=?+yUdSgrfHZO{d?aU2ziPdY%ZI*`f8`nQB>9?+J?r%YZKKQSi& zkDUS4dJo(k9LpuZ^&eeH6H=669duxuKjI zFU|pv>jQSqMFK9l9}}{lQY0t85Oi=+fbN0?;m5N40 zZD;}>fD1m~!obNPP+rjajzCvsObQz?^8z>3v(}dWnFh?H4$~SY&6|4tW#-h+mpLoI zo8XXxz7J^dab*eHh9o;Hxx?^LFR0&9(iM1Ea8v}`C>;$SNDhNFjz-f4q?AEv@sXNH b9!Tr_dUdaI))_(I)rbt9u6{1-oD!M Date: Tue, 17 Mar 2020 12:11:59 +0100 Subject: [PATCH 272/474] Changed bgc of testArea and played on pref size of list and scrollPane --- src/main/java/envoy/client/ui/ChatWindow.java | 5 +++-- .../java/envoy/client/ui/renderer/MessageListRenderer.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index eda61e4..c7f74f4 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -133,11 +133,12 @@ public class ChatWindow extends JFrame { // updates list elements when list is resized @Override public void componentResized(ComponentEvent e) { - messageList.synchronizeModel(); var prefSize = e.getComponent().getPreferredSize(); + e.getComponent().setPreferredSize(prefSize); + messageList.synchronizeModel(); messageList.setMinimumSize(new Dimension(prefSize.width, 0)); messageList.setMaximumSize(new Dimension(prefSize.width, Integer.MAX_VALUE)); - messageList.setPreferredSize(new Dimension(prefSize.width, messageList.getPreferredSize().height)); + messageList.setPreferredSize(new Dimension(prefSize.width, (int) messageList.getPreferredSize().getHeight())); } }); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java index 10bece5..e6622b4 100644 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java @@ -91,7 +91,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { messageTextArea.setWrapStyleWord(true); messageTextArea.setForeground(theme.getMessageTextColor()); messageTextArea.setAlignmentX(0.5f); - messageTextArea.setBackground(Color.RED); + messageTextArea.setBackground(theme.getCellColor()); messageTextArea.setEditable(false); var font = new Font("Arial", Font.PLAIN, 14); messageTextArea.setFont(font); From f10556ac440623fc2107514b67390e792878032a Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 17 Mar 2020 12:35:31 +0100 Subject: [PATCH 273/474] Fixed message list dimension --- src/main/java/envoy/client/ui/ChatWindow.java | 8 ++------ .../envoy/client/ui/renderer/MessageListRenderer.java | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index c7f74f4..182f824 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -130,15 +130,11 @@ public class ChatWindow extends JFrame { scrollPane.setViewportView(messageList); scrollPane.addComponentListener(new ComponentAdapter() { - // updates list elements when list is resized + // Update list elements when scroll pane (and thus list) is resized @Override public void componentResized(ComponentEvent e) { - var prefSize = e.getComponent().getPreferredSize(); - e.getComponent().setPreferredSize(prefSize); + messageList.setMaximumSize(new Dimension(scrollPane.getWidth(), Integer.MAX_VALUE)); messageList.synchronizeModel(); - messageList.setMinimumSize(new Dimension(prefSize.width, 0)); - messageList.setMaximumSize(new Dimension(prefSize.width, Integer.MAX_VALUE)); - messageList.setPreferredSize(new Dimension(prefSize.width, (int) messageList.getPreferredSize().getHeight())); } }); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java index e6622b4..27a5a0d 100644 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java @@ -95,7 +95,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { messageTextArea.setEditable(false); var font = new Font("Arial", Font.PLAIN, 14); messageTextArea.setFont(font); - messageTextArea.setSize(list.getWidth() - padding - 16, 10); + messageTextArea.setSize(list.getMaximumSize().width - padding - 16, 10); var gbc_messageTextArea = new GridBagConstraints(); gbc_messageTextArea.fill = GridBagConstraints.HORIZONTAL; @@ -129,7 +129,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, ours ? padding : 0, 10, ours ? 0 : padding), BorderFactory.createEtchedBorder())); - var size = new Dimension(list.getWidth(), panel.getPreferredSize().height); + var size = new Dimension(list.getMaximumSize().width - 50, panel.getPreferredSize().height); panel.setPreferredSize(size); panel.setMinimumSize(size); From 0007caa6f03e9808a59e3acacd8e6cdd4e19b330 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 17 Mar 2020 12:45:50 +0100 Subject: [PATCH 274/474] Added Javadoc to IconUtil --- src/main/java/envoy/client/ui/IconUtil.java | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main/java/envoy/client/ui/IconUtil.java b/src/main/java/envoy/client/ui/IconUtil.java index 47588ab..25d6513 100644 --- a/src/main/java/envoy/client/ui/IconUtil.java +++ b/src/main/java/envoy/client/ui/IconUtil.java @@ -9,6 +9,9 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; /** + * Provides static utility methods for loading icons from the resource + * folder.
+ *
* Project: envoy-client * File: IconUtil.java * Created: 16.03.2020 @@ -20,10 +23,34 @@ public class IconUtil { private IconUtil() {} + /** + * Loads an icon from resource folder and scales it to a given size. + * + * @param path the path to the icon inside the resource folder + * @param size the size to scale the icon to + * @return the scaled icon + * @throws IOException if the loading process failed + * @since Envoy v0.1-beta + */ public static ImageIcon load(String path, int size) throws IOException { return new ImageIcon(ImageIO.read(IconUtil.class.getResourceAsStream(path)).getScaledInstance(size, size, Image.SCALE_SMOOTH)); } + /** + * + * Loads icons specified by an enum. The images have to be named like the + * lowercase enum constants with {@code .png} extension and be located inside a + * folder with the lowercase name of the enum, which must be contained inside + * the {@code /icons} folder. + * + * @param the enum that specifies the icons to load + * @param enumClass the class of the enum + * @param size the size to scale the icons to + * @return a map containing the loaded icons with the corresponding enum + * constants as keys + * @throws IOException if the loading process failed + * @since Envoy v0.1-beta + */ public static > EnumMap loadByEnum(Class enumClass, int size) throws IOException { var icons = new EnumMap(enumClass); var path = "/icons/" + enumClass.getSimpleName().toLowerCase() + "/"; From a6b6a68a56e6675bfbff69d0ea4e0e979fcda999 Mon Sep 17 00:00:00 2001 From: delvh Date: Wed, 18 Mar 2020 08:03:35 +0100 Subject: [PATCH 275/474] Merged current working status of f/icon_util into f/forward__messages * added ContextMenu * added ContactsChooserDialog --- .../java/envoy/client/ui/ContextMenu.java | 184 ++++++++++++++++++ src/main/java/envoy/client/ui/Startup.java | 2 + .../client/ui/{ => container}/ChatWindow.java | 50 ++++- .../ui/container/ContactsChooserDialog.java | 125 ++++++++++++ .../ui/{ => container}/LoginDialog.java | 3 +- .../client/ui/container/package-info.java | 13 ++ .../envoy/client/ui/list/ComponentList.java | 11 +- 7 files changed, 375 insertions(+), 13 deletions(-) create mode 100644 src/main/java/envoy/client/ui/ContextMenu.java rename src/main/java/envoy/client/ui/{ => container}/ChatWindow.java (92%) create mode 100644 src/main/java/envoy/client/ui/container/ContactsChooserDialog.java rename src/main/java/envoy/client/ui/{ => container}/LoginDialog.java (99%) create mode 100644 src/main/java/envoy/client/ui/container/package-info.java diff --git a/src/main/java/envoy/client/ui/ContextMenu.java b/src/main/java/envoy/client/ui/ContextMenu.java new file mode 100644 index 0000000..7328b0d --- /dev/null +++ b/src/main/java/envoy/client/ui/ContextMenu.java @@ -0,0 +1,184 @@ +package envoy.client.ui; + +import java.awt.Component; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.*; + +/** + * This class defines a menu that will be automatically called if + * {@link MouseEvent#isPopupTrigger()} returns true for the parent component. + * The user has the possibility to directly add actions to be performed when + * clicking on the element with the selected String. Additionally, for each + * element an {@link Icon} can be added, but it must not be. + * If the key(text) of an element starts with one of the predefined values, a + * special component will be called: either a {@link JRadioButtonMenuItem}, a + * {@link JCheckBoxMenuItem} or a {@link JMenu} will be created.
+ *
+ * Project: envoy-client
+ * File: ContextMenu.java
+ * Created: 17 Mar 2020
+ * + * @author Leon Hofmeister + * @since Envoy v0.1-beta + */ +public class ContextMenu extends JPopupMenu { + + private static final long serialVersionUID = 2177146471226992104L; + + /** + * If a key starts with this String, a {@link JCheckBoxMenuItem} will be created + */ + public static final String checkboxMenuItem = "ChBoMI"; + /** + * If a key starts with this String, a {@link JRadioButtonMenuItem} will be + * created + */ + public static final String radioButtonMenuItem = "RaBuMI"; + /** + * If a key starts with this String, a {@link JMenu} will be created + */ + public static final String subMenuItem = "SubMI"; + + private Map items = new HashMap<>(); + private Map icons = new HashMap<>(); + + private ButtonGroup radioButtonGroup = new ButtonGroup(); + private boolean built = false; + private boolean visible = false; + + /** + * @since Envoy v0.1-beta + */ + public ContextMenu() {} + + /** + * @param label the string that a UI may use to display as a title + * for the pop-up menu + * @param parent the component which will call this + * {@link ContextMenu} + * @param itemsWithActions a map of all strings to be displayed with according + * actions + * @param itemIcons the icons to be displayed before a name, if wanted. + * Only keys in here will have an Icon displayed. More + * precisely, all keys here not included in the first + * map will be thrown out. + * @since Envoy v0.1-beta + */ + public ContextMenu(String label, Component parent, Map itemsWithActions, Map itemIcons) { + super(label); + setInvoker(parent); + this.items = (itemsWithActions != null) ? itemsWithActions : items; + this.icons = (itemIcons != null) ? itemIcons : icons; + } + + /** + * Prepares the PopupMenu to be displayed. Should only be used once all map + * values have been set. + * + * @return this instance of {@link ContextMenu} to allow chaining behind the + * constructor + * @since Envoy v0.1-beta + */ + public ContextMenu build() { + items.forEach((text, action) -> { + // case radio button wanted + if (text.startsWith(radioButtonMenuItem)) { + var item = new JRadioButtonMenuItem(text.substring(radioButtonMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); + item.addActionListener(action); + radioButtonGroup.add(item); + add(item); + // case check box wanted + } else if (text.startsWith(checkboxMenuItem)) { + var item = new JCheckBoxMenuItem(text.substring(checkboxMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); + item.addActionListener(action); + add(item); + // case sub-menu wanted + } else if (text.startsWith(subMenuItem)) { + var item = new JMenu(text.substring(subMenuItem.length())); + item.addActionListener(action); + add(item); + } else { + // normal JMenuItem wanted + var item = new JMenuItem(text, icons.containsKey(text) ? icons.get(text) : null); + item.addActionListener(action); + add(item); + } + }); + getInvoker().addMouseListener(getShowingListener()); + built = true; + return this; + } + + /** + * @param label the string that a UI may use to display as a title for the + * pop-up menu. + * @since Envoy v0.1-beta + */ + public ContextMenu(String label) { super(label); } + + private MouseAdapter getShowingListener() { + return new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { action(e); } + + @Override + public void mousePressed(MouseEvent e) { action(e); } + + @Override + public void mouseReleased(MouseEvent e) { action(e); } + + private void action(MouseEvent e) { + if (!built) build(); + if (e.isPopupTrigger()) { + show(e.getComponent(), e.getX(), e.getY()); + // hides the menu if already visible + visible = !visible; + setVisible(visible); + + } + } + }; + } + + /** + * Removes all subcomponents of this menu. + * + * @since Envoy v0.1-beta + */ + public void clear() { + removeAll(); + items = new HashMap<>(); + icons = new HashMap<>(); + } + + /** + * @return the items + * @since Envoy v0.1-beta + */ + public Map getItems() { return items; } + + /** + * @param items the items with the displayed text and the according action to + * take once called + * @since Envoy v0.1-beta + */ + public void setItems(Map items) { this.items = items; } + + /** + * @return the icons + * @since Envoy v0.1-beta + */ + public Map getIcons() { return icons; } + + /** + * @param icons the icons to set + * @since Envoy v0.1-beta + */ + public void setIcons(Map icons) { this.icons = icons; } +} diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 8f44c2a..5c03881 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -15,6 +15,8 @@ import javax.swing.SwingUtilities; import envoy.client.data.*; import envoy.client.net.Client; import envoy.client.net.WriteProxy; +import envoy.client.ui.container.ChatWindow; +import envoy.client.ui.container.LoginDialog; import envoy.data.Config; import envoy.data.Message; import envoy.data.User.UserStatus; diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java similarity index 92% rename from src/main/java/envoy/client/ui/ChatWindow.java rename to src/main/java/envoy/client/ui/container/ChatWindow.java index 182f824..fc43f89 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -1,8 +1,12 @@ -package envoy.client.ui; +package envoy.client.ui.container; import java.awt.*; +import java.awt.datatransfer.StringSelection; import java.awt.event.*; import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -18,13 +22,13 @@ import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.net.Client; import envoy.client.net.WriteProxy; +import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListModel; import envoy.client.ui.primary.PrimaryButton; import envoy.client.ui.primary.PrimaryScrollPane; import envoy.client.ui.primary.PrimaryTextArea; import envoy.client.ui.renderer.ContactsSearchRenderer; -import envoy.client.ui.renderer.MessageListRenderer; import envoy.client.ui.renderer.UserListRenderer; import envoy.client.ui.settings.SettingsScreen; import envoy.data.Message; @@ -103,7 +107,6 @@ public class ChatWindow extends JFrame { public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); - setMinimumSize(new Dimension(400, 300)); setTitle("Envoy"); setLocationRelativeTo(null); setIconImage(Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); @@ -123,19 +126,39 @@ public class ChatWindow extends JFrame { @Override public void mouseClicked(MouseEvent e) { if (e.isPopupTrigger()) { + contextMenu = new JPopupMenu("message options"); + Map commands = new HashMap<>() { + private static final long serialVersionUID = -2755235774946990126L; + + { + put("forward selected message", + evt -> forwardMessageToMultipleUsers(messageList.getSelected().get(0), + ContactsChooserDialog + .showForwardingDialog("Forward selected message to", messageList.getSelected().get(0), client))); + put("copy", evt -> { + // TODO should be enhanced to allow also copying of message attachments, + // especially pictures + StringSelection copy = new StringSelection(messageList.getSelected().get(0).getText()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); + }); + // TODO insert implementation to edit and delete messages + put("delete", evt -> {}); + put("edit", evt -> {}); + put("quote", evt -> {}); + } + }; + commands.forEach((name, action) -> { var item = new JMenuItem(name); item.addActionListener(action); contextMenu.add(item); }); + contextMenu.show(e.getComponent(), e.getX(), e.getY()); } } }); scrollPane.setViewportView(messageList); scrollPane.addComponentListener(new ComponentAdapter() { - // Update list elements when scroll pane (and thus list) is resized + // updates list elements when list is resized @Override - public void componentResized(ComponentEvent e) { - messageList.setMaximumSize(new Dimension(scrollPane.getWidth(), Integer.MAX_VALUE)); - messageList.synchronizeModel(); - } + public void componentResized(ComponentEvent e) { messageList.synchronizeModel(); } }); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); @@ -538,6 +561,15 @@ public class ChatWindow extends JFrame { sendMessage(new MessageBuilder(msg, recipient.getId(), localDb.getIdGenerator()).build()); } + private void forwardMessageToMultipleUsers(Message message, Collection recipients) { + recipients.forEach(recipient -> forwardMessage(message, recipient)); + } + + @SuppressWarnings("unused") + private void forwardMultipleMessagesToMultipleUsers(Collection messages, Collection recipients) { + messages.forEach(message -> forwardMessageToMultipleUsers(message, recipients)); + } + /** * Sends a {@link Message} to the server. * @@ -612,8 +644,6 @@ public class ChatWindow extends JFrame { this.localDb = localDb; this.writeProxy = writeProxy; - messageList.setRenderer(new MessageListRenderer(client.getSender().getId())); - // Load users and chats new Thread(() -> { localDb.getUsers().values().forEach(user -> { diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java new file mode 100644 index 0000000..b82707b --- /dev/null +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -0,0 +1,125 @@ +package envoy.client.ui.container; + +import java.awt.BorderLayout; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; + +import envoy.client.data.Settings; +import envoy.client.net.Client; +import envoy.client.ui.Theme; +import envoy.client.ui.list.ComponentList; +import envoy.client.ui.list.ComponentListModel; +import envoy.client.ui.renderer.MessageListRenderer; +import envoy.client.ui.renderer.UserComponentListRenderer; +import envoy.data.Message; +import envoy.data.User; + +/** + * This class defines a dialog to choose contacts from.
+ *
+ * Project: envoy-client
+ * File: ContactsChooserDialog.java
+ * Created: 15 Mar 2020
+ * + * @author Leon Hofmeister + * @since Envoy v0.1-beta + */ +public class ContactsChooserDialog extends JDialog { + + private static final long serialVersionUID = -5774558118579032256L; + + private ComponentList contactList = new ComponentList<>(new UserComponentListRenderer()); + private JButton okButton = new JButton("Ok"); + private JButton cancelButton = new JButton("Cancel"); + + private final Theme theme = Settings.getInstance().getTheme(Settings.getInstance().getCurrentTheme()); + + private final JPanel contentPanel = new JPanel(); + + /** + * Shows a modal contacts-chooser dialog and blocks until the + * dialog is hidden. If the user presses the "OK" button, then + * this method hides/disposes the dialog and returns the selected element (has + * yet + * to be casted back to its original type due to the limitations of Generics in + * Java). + * If the user presses the "Cancel" button or closes the dialog without + * pressing "OK", then this method disposes the dialog and returns an empty + * ArrayList. + * + * @param title the title of the dialog + * @param message the {@link Message} to display on top of the Dialog + * @param client the client whose contacts should be displayed + * @return the selected Element (yet has to be casted to the wanted type due to + * the Generics limitations in Java) + * @since Envoy v0.1-beta + */ + public static List showForwardingDialog(String title, Message message, Client client) { + ContactsChooserDialog dialog = new ContactsChooserDialog(); + dialog.setTitle(title); + dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE); + dialog.addCancelButtonActionListener(e -> dialog.dispose()); + dialog.getContentPanel() + .add(new MessageListRenderer(client.getSender().getId()).getListCellComponent(null, message, false), BorderLayout.NORTH); + List results = new ArrayList<>(); + dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelected()); dialog.dispose(); }); + ComponentListModel contactListModel = dialog.getContactList().getModel(); + client.getContacts().getContacts().forEach(user -> contactListModel.add(user)); + dialog.setVisible(true); + dialog.repaint(); + dialog.revalidate(); + return results.size() > 0 ? results : null; + } + + /** + * @since Envoy v0.1-beta + */ + private ContactsChooserDialog() { + contactList.enableMultipleSelection(); + // setBounds(100, 100, 450, 300); + setModal(true); + getContentPane().setLayout(new BorderLayout()); + setBackground(theme.getBackgroundColor()); + setForeground(theme.getMessageTextColor()); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + contentPanel.setLayout(new BorderLayout(0, 0)); + contentPanel.add(contactList, BorderLayout.CENTER); + { + JPanel buttonPane = new JPanel(); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + { + JButton okButton = new JButton("OK"); + okButton.setMnemonic(KeyEvent.VK_ENTER); + okButton.setActionCommand("OK"); + buttonPane.setLayout(new BorderLayout(0, 0)); + buttonPane.add(okButton, BorderLayout.EAST); + getRootPane().setDefaultButton(okButton); + } + { + JButton cancelButton = new JButton("Cancel"); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton, BorderLayout.WEST); + } + } + } + + /** + * @return the underlying {@link ComponentList} + * @since Envoy v0.1-beta + */ + private ComponentList getContactList() { return contactList; } + + private void addOkButtonActionListener(ActionListener l) { okButton.addActionListener(l); } + + private void addCancelButtonActionListener(ActionListener l) { cancelButton.addActionListener(l); } + + private JPanel getContentPanel() { return contentPanel; } +} diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/container/LoginDialog.java similarity index 99% rename from src/main/java/envoy/client/ui/LoginDialog.java rename to src/main/java/envoy/client/ui/container/LoginDialog.java index 9cd645d..51d9817 100644 --- a/src/main/java/envoy/client/ui/LoginDialog.java +++ b/src/main/java/envoy/client/ui/container/LoginDialog.java @@ -1,4 +1,4 @@ -package envoy.client.ui; +package envoy.client.ui.container; import java.awt.*; import java.awt.event.ItemEvent; @@ -16,6 +16,7 @@ import javax.swing.border.EmptyBorder; import envoy.client.data.*; import envoy.client.event.HandshakeSuccessfulEvent; import envoy.client.net.Client; +import envoy.client.ui.Theme; import envoy.client.ui.primary.PrimaryButton; import envoy.data.LoginCredentials; import envoy.data.Message; diff --git a/src/main/java/envoy/client/ui/container/package-info.java b/src/main/java/envoy/client/ui/container/package-info.java new file mode 100644 index 0000000..27645f4 --- /dev/null +++ b/src/main/java/envoy/client/ui/container/package-info.java @@ -0,0 +1,13 @@ +/** + * This package contains all graphical Containers, like Dialogs and Frames.
+ *
+ * Project: envoy-client
+ * File: package-info.java
+ * Created: 16 Mar 2020
+ * + * @author Leon Hofmeister + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.1-beta + */ +package envoy.client.ui.container; diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 3d90ea9..b6962e3 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -108,6 +108,10 @@ public class ComponentList extends JPanel { * @since Envoy v0.1-beta */ private void add(E elem, int index, boolean isSelected) { + if (isSelected && !multipleSelectionEnabled) { + clearSelections(); + currentSelections.add(index); + } final JComponent component = renderer.getListCellComponent(this, elem, isSelected); component.addMouseListener(getSelectionListener(index)); add(component, index); @@ -169,7 +173,7 @@ public class ComponentList extends JPanel { * @since Envoy v0.1-beta */ private void clearSelections() { - currentSelections.forEach(index2 -> updateSelection(index2, false)); + currentSelections.forEach(index -> updateSelection(index, false)); currentSelections.clear(); } @@ -224,7 +228,10 @@ public class ComponentList extends JPanel { * the component list * @since Envoy v0.1-beta */ - public void setMultipleSelectionEnabled(boolean multipleSelectionEnabled) { this.multipleSelectionEnabled = multipleSelectionEnabled; } + public void setMultipleSelectionEnabled(boolean multipleSelectionEnabled) { + this.multipleSelectionEnabled = multipleSelectionEnabled; + if (!multipleSelectionEnabled) clearSelections(); + } /** * Enables the selection of multiple elements. From ad59fe095810aaf61ccd7d3309aa95b047e2f245 Mon Sep 17 00:00:00 2001 From: delvh Date: Wed, 18 Mar 2020 22:13:58 +0100 Subject: [PATCH 276/474] added missing merge content,mnemonics support(ContextMenu)and Nullchecks --- .../java/envoy/client/ui/ContextMenu.java | 73 ++++++++++++------- .../envoy/client/ui/container/ChatWindow.java | 63 ++++++++-------- .../envoy/client/ui/list/ComponentList.java | 18 ++++- .../client/ui/list/ComponentListModel.java | 2 +- 4 files changed, 91 insertions(+), 65 deletions(-) diff --git a/src/main/java/envoy/client/ui/ContextMenu.java b/src/main/java/envoy/client/ui/ContextMenu.java index 7328b0d..1ba5d14 100644 --- a/src/main/java/envoy/client/ui/ContextMenu.java +++ b/src/main/java/envoy/client/ui/ContextMenu.java @@ -44,17 +44,20 @@ public class ContextMenu extends JPopupMenu { */ public static final String subMenuItem = "SubMI"; - private Map items = new HashMap<>(); - private Map icons = new HashMap<>(); + private Map items = new HashMap<>(); + private Map icons = new HashMap<>(); + private Map mnemonics = new HashMap<>(); private ButtonGroup radioButtonGroup = new ButtonGroup(); private boolean built = false; private boolean visible = false; /** + * @param parent the component which will call this + * {@link ContextMenu} * @since Envoy v0.1-beta */ - public ContextMenu() {} + public ContextMenu(Component parent) { setInvoker(parent); } /** * @param label the string that a UI may use to display as a title @@ -67,13 +70,18 @@ public class ContextMenu extends JPopupMenu { * Only keys in here will have an Icon displayed. More * precisely, all keys here not included in the first * map will be thrown out. + * @param itemMnemonics the keyboard shortcuts that need to be pressed to + * automatically execute the {@link JMenuItem} with the + * given text * @since Envoy v0.1-beta */ - public ContextMenu(String label, Component parent, Map itemsWithActions, Map itemIcons) { + public ContextMenu(String label, Component parent, Map itemsWithActions, Map itemIcons, + Map itemMnemonics) { super(label); setInvoker(parent); - this.items = (itemsWithActions != null) ? itemsWithActions : items; - this.icons = (itemIcons != null) ? itemIcons : icons; + this.items = (itemsWithActions != null) ? itemsWithActions : items; + this.icons = (itemIcons != null) ? itemIcons : icons; + this.mnemonics = (itemMnemonics != null) ? itemMnemonics : mnemonics; } /** @@ -87,27 +95,20 @@ public class ContextMenu extends JPopupMenu { public ContextMenu build() { items.forEach((text, action) -> { // case radio button wanted + AbstractButton item; if (text.startsWith(radioButtonMenuItem)) { - var item = new JRadioButtonMenuItem(text.substring(radioButtonMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); - item.addActionListener(action); + item = new JRadioButtonMenuItem(text.substring(radioButtonMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); radioButtonGroup.add(item); - add(item); // case check box wanted - } else if (text.startsWith(checkboxMenuItem)) { - var item = new JCheckBoxMenuItem(text.substring(checkboxMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); - item.addActionListener(action); - add(item); - // case sub-menu wanted - } else if (text.startsWith(subMenuItem)) { - var item = new JMenu(text.substring(subMenuItem.length())); - item.addActionListener(action); - add(item); - } else { - // normal JMenuItem wanted - var item = new JMenuItem(text, icons.containsKey(text) ? icons.get(text) : null); - item.addActionListener(action); - add(item); - } + } else if (text.startsWith(checkboxMenuItem)) + item = new JCheckBoxMenuItem(text.substring(checkboxMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); + // case sub-menu wanted + else if (text.startsWith(subMenuItem)) item = new JMenu(text.substring(subMenuItem.length())); + else // normal JMenuItem wanted + item = new JMenuItem(text, icons.containsKey(text) ? icons.get(text) : null); + item.addActionListener(action); + if (mnemonics.containsKey(text)) item.setMnemonic(mnemonics.get(text)); + add(item); }); getInvoker().addMouseListener(getShowingListener()); built = true; @@ -136,10 +137,10 @@ public class ContextMenu extends JPopupMenu { private void action(MouseEvent e) { if (!built) build(); if (e.isPopupTrigger()) { - show(e.getComponent(), e.getX(), e.getY()); // hides the menu if already visible visible = !visible; - setVisible(visible); + if (visible) show(e.getComponent(), e.getX(), e.getY()); + else setVisible(false); } } @@ -153,8 +154,9 @@ public class ContextMenu extends JPopupMenu { */ public void clear() { removeAll(); - items = new HashMap<>(); - icons = new HashMap<>(); + items = new HashMap<>(); + icons = new HashMap<>(); + mnemonics = new HashMap<>(); } /** @@ -181,4 +183,19 @@ public class ContextMenu extends JPopupMenu { * @since Envoy v0.1-beta */ public void setIcons(Map icons) { this.icons = icons; } + + /** + * @return the mnemonics (the keyboard shortcuts that automatically execute the + * command for a {@link JMenuItem} with corresponding text) + * @since Envoy v0.1-beta + */ + public Map getMnemonics() { return mnemonics; } + + /** + * @param mnemonics the keyboard shortcuts that need to be pressed to + * automatically execute the {@link JMenuItem} with the given + * text + * @since Envoy v0.1-beta + */ + public void setMnemonics(Map mnemonics) { this.mnemonics = mnemonics; } } diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index fc43f89..a21d99a 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -22,6 +22,7 @@ import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.net.Client; import envoy.client.net.WriteProxy; +import envoy.client.ui.ContextMenu; import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListModel; @@ -29,6 +30,7 @@ import envoy.client.ui.primary.PrimaryButton; import envoy.client.ui.primary.PrimaryScrollPane; import envoy.client.ui.primary.PrimaryTextArea; import envoy.client.ui.renderer.ContactsSearchRenderer; +import envoy.client.ui.renderer.MessageListRenderer; import envoy.client.ui.renderer.UserListRenderer; import envoy.client.ui.settings.SettingsScreen; import envoy.data.Message; @@ -74,6 +76,7 @@ public class ChatWindow extends JFrame { private JTextPane textPane = new JTextPane(); private PrimaryButton postButton = new PrimaryButton("Post"); private PrimaryButton settingsButton = new PrimaryButton("Settings"); + @SuppressWarnings("unused") private JPopupMenu contextMenu; // Contacts Header @@ -107,6 +110,7 @@ public class ChatWindow extends JFrame { public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); + setMinimumSize(new Dimension(400, 300)); setTitle("Envoy"); setLocationRelativeTo(null); setIconImage(Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); @@ -121,44 +125,37 @@ public class ChatWindow extends JFrame { contentPane.setLayout(gbl_contentPane); messageList.setBorder(new EmptyBorder(space, space, space, space)); - messageList.addMouseListener(new MouseAdapter() { + Map commands = new HashMap<>() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.isPopupTrigger()) { - contextMenu = new JPopupMenu("message options"); - Map commands = new HashMap<>() { + private static final long serialVersionUID = -2755235774946990126L; - private static final long serialVersionUID = -2755235774946990126L; - - { - put("forward selected message", - evt -> forwardMessageToMultipleUsers(messageList.getSelected().get(0), - ContactsChooserDialog - .showForwardingDialog("Forward selected message to", messageList.getSelected().get(0), client))); - put("copy", evt -> { - // TODO should be enhanced to allow also copying of message attachments, - // especially pictures - StringSelection copy = new StringSelection(messageList.getSelected().get(0).getText()); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); - }); - // TODO insert implementation to edit and delete messages - put("delete", evt -> {}); - put("edit", evt -> {}); - put("quote", evt -> {}); - } - }; - commands.forEach((name, action) -> { var item = new JMenuItem(name); item.addActionListener(action); contextMenu.add(item); }); - contextMenu.show(e.getComponent(), e.getX(), e.getY()); - } + { + put("forward selected message", + evt -> forwardMessageToMultipleUsers(messageList.getSelected().get(0), + ContactsChooserDialog.showForwardingDialog("Forward selected message to", messageList.getSelected().get(0), client))); + put("copy", evt -> { + // TODO should be enhanced to allow also copying of message attachments, + // especially pictures + StringSelection copy = new StringSelection(messageList.getSelected().get(0).getText()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); + }); + // TODO insert implementation to edit and delete messages + put("delete", evt -> {}); + put("edit", evt -> {}); + put("quote", evt -> {}); } - }); + }; + contextMenu = new ContextMenu(null, messageList, commands, null, null).build(); + scrollPane.setViewportView(messageList); scrollPane.addComponentListener(new ComponentAdapter() { - // updates list elements when list is resized + // Update list elements when scroll pane (and thus list) is resized @Override - public void componentResized(ComponentEvent e) { messageList.synchronizeModel(); } + public void componentResized(ComponentEvent e) { + messageList.setMaximumSize(new Dimension(scrollPane.getWidth(), Integer.MAX_VALUE)); + messageList.synchronizeModel(); + } }); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); @@ -600,7 +597,7 @@ public class ChatWindow extends JFrame { private void readCurrentChat() { try { currentChat.read(writeProxy); - messageList.synchronizeModel(); + if (messageList.getRenderer() != null) messageList.synchronizeModel(); } catch (IOException e) { e.printStackTrace(); logger.log(Level.WARNING, "Couldn't notify server about message status change", e); @@ -644,6 +641,8 @@ public class ChatWindow extends JFrame { this.localDb = localDb; this.writeProxy = writeProxy; + messageList.setRenderer(new MessageListRenderer(client.getSender().getId())); + // Load users and chats new Thread(() -> { localDb.getUsers().values().forEach(user -> { diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index b6962e3..8b7ec43 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -31,6 +31,12 @@ public class ComponentList extends JPanel { private static final long serialVersionUID = 1759644503942876737L; + /** + * Sets the layout of this {@link ComponentList} to be a vertically oriented + * BoxLayout. + * + * @since Envoy v0.1-beta + */ public ComponentList() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); } /** @@ -74,7 +80,7 @@ public class ComponentList extends JPanel { // Synchronize with new model this.model = model; if (model != null) this.model.setComponentList(this); - synchronizeModel(); + if (renderer != null) synchronizeModel(); } /** @@ -84,9 +90,11 @@ public class ComponentList extends JPanel { * @since Envoy v0.3-alpha */ public void synchronizeModel() { - removeAll(); - if (model != null) model.forEach(this::add); - revalidate(); + if (model != null && renderer != null) { + removeAll(); + model.forEach(this::add); + revalidate(); + } } /** @@ -112,9 +120,11 @@ public class ComponentList extends JPanel { clearSelections(); currentSelections.add(index); } + if (renderer != null) { final JComponent component = renderer.getListCellComponent(this, elem, isSelected); component.addMouseListener(getSelectionListener(index)); add(component, index); + } } /** diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java index 95775c1..aad379e 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -115,6 +115,6 @@ public final class ComponentListModel implements Iterable, Serializable { */ void setComponentList(ComponentList componentList) { this.componentList = componentList; - if (componentList != null) componentList.synchronizeModel(); + if (componentList != null && componentList.getRenderer() != null) componentList.synchronizeModel(); } } From 6d6397cfd4c3b92ae57388e815ae36d97e631551 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 19 Mar 2020 21:52:06 +0100 Subject: [PATCH 277/474] Unrelated cleanup in UserComponentListRenderer --- .../renderer/UserComponentListRenderer.java | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java b/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java index e86214b..f19f17e 100644 --- a/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java @@ -9,6 +9,7 @@ import javax.swing.JLabel; import javax.swing.JPanel; import envoy.client.data.Settings; +import envoy.client.ui.Color; import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; @@ -28,46 +29,42 @@ public class UserComponentListRenderer implements ComponentListCellRenderer list, User value, boolean isSelected) { + public JComponent getListCellComponent(ComponentList list, User user, boolean isSelected) { + final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + final JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); - final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); // Panel background panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); panel.setOpaque(true); - panel.setPreferredSize(new Dimension(100, 35)); // TODO add profile picture support in BorderLayout.West - JLabel username = new JLabel(value.getName()); + JLabel username = new JLabel(user.getName()); username.setForeground(theme.getUserNameColor()); panel.add(username, BorderLayout.CENTER); - final UserStatus status = value.getStatus(); + final UserStatus status = user.getStatus(); JLabel statusLabel = new JLabel(status.toString()); - java.awt.Color foreground; + Color foreground; switch (status) { - case OFFLINE: - foreground = java.awt.Color.LIGHT_GRAY; - break; case AWAY: - foreground = java.awt.Color.YELLOW; + foreground = Color.yellow; break; case BUSY: - foreground = java.awt.Color.BLUE; + foreground = Color.blue; break; case ONLINE: - foreground = java.awt.Color.GREEN; + foreground = Color.green; break; default: - foreground = java.awt.Color.LIGHT_GRAY; + foreground = Color.lightGray; break; } statusLabel.setForeground(foreground); panel.add(statusLabel, BorderLayout.NORTH); return panel; } - } From f5ddadf4d055e1d2050b89e6e64dab76f5598e18 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 19 Mar 2020 22:16:31 +0100 Subject: [PATCH 278/474] Added SelectionMode enum to ComponentList, prepared integration These changes are not ready to build yet, as ChatWindow and ContactsChooserDialog have to be adjusted first. --- .../envoy/client/ui/container/ChatWindow.java | 6 +- .../ui/container/ContactsChooserDialog.java | 2 +- .../envoy/client/ui/list/ComponentList.java | 198 ++++++++---------- .../client/ui/list/ComponentListModel.java | 2 +- 4 files changed, 89 insertions(+), 119 deletions(-) diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index a21d99a..a41a465 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -131,12 +131,12 @@ public class ChatWindow extends JFrame { { put("forward selected message", - evt -> forwardMessageToMultipleUsers(messageList.getSelected().get(0), - ContactsChooserDialog.showForwardingDialog("Forward selected message to", messageList.getSelected().get(0), client))); + evt -> forwardMessageToMultipleUsers(messageList.getSelection().get(0), + ContactsChooserDialog.showForwardingDialog("Forward selected message to", messageList.getSelection().get(0), client))); put("copy", evt -> { // TODO should be enhanced to allow also copying of message attachments, // especially pictures - StringSelection copy = new StringSelection(messageList.getSelected().get(0).getText()); + StringSelection copy = new StringSelection(messageList.getSelection().get(0).getText()); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); }); // TODO insert implementation to edit and delete messages diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java index b82707b..b85f9a8 100644 --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -69,7 +69,7 @@ public class ContactsChooserDialog extends JDialog { dialog.getContentPanel() .add(new MessageListRenderer(client.getSender().getId()).getListCellComponent(null, message, false), BorderLayout.NORTH); List results = new ArrayList<>(); - dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelected()); dialog.dispose(); }); + dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelection()); dialog.dispose(); }); ComponentListModel contactListModel = dialog.getContactList().getModel(); client.getContacts().getContacts().forEach(user -> contactListModel.add(user)); dialog.setVisible(true); diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 8b7ec43..2cac513 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -3,8 +3,8 @@ package envoy.client.ui.list; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; -import java.util.ArrayList; -import java.util.List; +import java.util.HashSet; +import java.util.Set; import javax.swing.*; @@ -25,15 +25,17 @@ public class ComponentList extends JPanel { private ComponentListModel model; private ComponentListCellRenderer renderer; - private boolean multipleSelectionEnabled = false; - - private List currentSelections = new ArrayList<>(); + private SelectionMode selectionMode = SelectionMode.NONE; + private Set selection = new HashSet<>(); private static final long serialVersionUID = 1759644503942876737L; + public static enum SelectionMode { + NONE, SINGLE, MULTIPLE + } + /** - * Sets the layout of this {@link ComponentList} to be a vertically oriented - * BoxLayout. + * Initializes a default {@link ComponentList} without a model or a renderer. * * @since Envoy v0.1-beta */ @@ -79,8 +81,8 @@ public class ComponentList extends JPanel { // Synchronize with new model this.model = model; - if (model != null) this.model.setComponentList(this); - if (renderer != null) synchronizeModel(); + if (model != null) model.setComponentList(this); + synchronizeModel(); } /** @@ -92,11 +94,53 @@ public class ComponentList extends JPanel { public void synchronizeModel() { if (model != null && renderer != null) { removeAll(); - model.forEach(this::add); + model.forEach(this::addElement); revalidate(); } } + /** + * Selects a list element by index. If the element is already selected, it is + * removed from the selection. + * + * @param index the index of the selected component + * @since Envoy v0.1-beta + */ + public void selectElement(int index) { + if (selection.contains(index)) { + + // Remove selection of element at index + updateElement(index, false); + selection.remove(index); + } else { + + // Remove old selection if single selection is enabled + if (selectionMode == SelectionMode.SINGLE) clearSelection(); + + if (selectionMode != SelectionMode.NONE) { + + // Assign new selection + selection.add(index); + + // Update element + updateElement(index, true); + } + } + + revalidate(); + repaint(); + } + + /** + * Removes the current selection. + * + * @since Envoy v0.1-alpha + */ + public void clearSelection() { + selection.forEach(i -> updateElement(i, false)); + selection.clear(); + } + /** * Adds an object to the list by rendering it with the current * {@link ComponentListCellRenderer}. @@ -104,89 +148,26 @@ public class ComponentList extends JPanel { * @param elem the element to add * @since Envoy v0.3-alpha */ - void add(E elem) { add(elem, getComponentCount(), false); } + void addElement(E elem) { addElement(elem, getComponentCount(), false); } /** * Adds an object to the list by rendering it with the current - * {@link ComponentListRenderer}. + * {@link ComponentListRenderer}. If the renderer is {@code null}, no action is + * performed. * * @param elem the element to add * @param index the index at which to add the element * @param isSelected the selection state of the element * @since Envoy v0.1-beta */ - private void add(E elem, int index, boolean isSelected) { - if (isSelected && !multipleSelectionEnabled) { - clearSelections(); - currentSelections.add(index); - } + private void addElement(E elem, int index, boolean isSelected) { if (renderer != null) { - final JComponent component = renderer.getListCellComponent(this, elem, isSelected); - component.addMouseListener(getSelectionListener(index)); - add(component, index); + final JComponent component = renderer.getListCellComponent(this, elem, isSelected); + component.addMouseListener(getSelectionListener(index)); + add(component, index); } } - /** - * @param componentIndex the index of the list component to which the mouse - * listener will be added - * @return a mouse listener calling the - * {@link ComponentList#componentSelected(int)} method with the - * component's index when a left click is performed by the user - * @since Envoy v0.1-beta - */ - private MouseListener getSelectionListener(int componentIndex) { - return new MouseAdapter() { - - @Override - public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) componentSelected(componentIndex); } - }; - } - - /** - * Gets called when a list component has been clicked on by the user. Any - * previous selections are then removed and the selected component gets - * redrawn.
- *
- * If the currently selected component gets selected again, the selection is - * removed. - * - * @param index the index of the selected component - * @since Envoy v0.1-beta - */ - private void componentSelected(int index) { - // removing selection of element at index - if (currentSelections.contains(index)) { - - // Clear selection - updateSelection(index, false); - currentSelections.remove(Integer.valueOf(index)); - } else { - - // Remove old selection if multipleSelection is disabled - if (!multipleSelectionEnabled && currentSelections.size() > 0) clearSelections(); - - // Assign new selection - currentSelections.add(index); - - // Update current selection - updateSelection(index, true); - } - - revalidate(); - repaint(); - } - - /** - * Clears all currently active selections. - * - * @since Envoy v0.1-beta - */ - private void clearSelections() { - currentSelections.forEach(index -> updateSelection(index, false)); - currentSelections.clear(); - } - /** * Replaces a list element with a newly rendered instance of its contents. * @@ -194,21 +175,33 @@ public class ComponentList extends JPanel { * @param isSelected the selection state passed to the {@link ListCellRenderer} * @since Envoy v0.1-beta */ - private void updateSelection(int index, boolean isSelected) { + private void updateElement(int index, boolean isSelected) { remove(index); - add(model.get(index), index, isSelected); + addElement(model.get(index), index, isSelected); } /** - * @return the selected elements or null if none is selected + * @param componentIndex the index of the list component to which the mouse + * listener will be added + * @return a mouse listener calling the + * {@link ComponentList#selectElement(int)} method with the + * component's index when a left click is performed by the user * @since Envoy v0.1-beta */ - public List getSelected() { - List selected = new ArrayList<>(); - currentSelections.forEach(index -> selected.add(model.get(index))); - return selected; + private MouseListener getSelectionListener(int componentIndex) { + return new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) selectElement(componentIndex); } + }; } + /** + * @return a set of all selected indices + * @since Envoy v0.1-beta + */ + public Set getSelection() { return selection; } + /** * @return the model * @since Envoy v0.1-beta @@ -228,37 +221,14 @@ public class ComponentList extends JPanel { public void setRenderer(ComponentListCellRenderer renderer) { this.renderer = renderer; } /** - * @return the multipleSelectionEnabled + * @return the selectionMode * @since Envoy v0.1-beta */ - public boolean isMultipleSelectionEnabled() { return multipleSelectionEnabled; } + public SelectionMode getSelectionMode() { return selectionMode; } /** - * @param multipleSelectionEnabled if true, multiple elements can be selected in - * the component list + * @param selectionMode the selectionMode to set * @since Envoy v0.1-beta */ - public void setMultipleSelectionEnabled(boolean multipleSelectionEnabled) { - this.multipleSelectionEnabled = multipleSelectionEnabled; - if (!multipleSelectionEnabled) clearSelections(); - } - - /** - * Enables the selection of multiple elements. - * - * @see ComponentList#disableMultipleSelection - * @since Envoy v0.1-beta - */ - public void enableMultipleSelection() { this.multipleSelectionEnabled = true; } - - /** - * Allows only one element to be selected. True by default. - * - * @see ComponentList#enableMultipleSelection - * @since Envoy v0.1-beta - */ - public void disableMultipleSelection() { - this.multipleSelectionEnabled = false; - clearSelections(); - } + public void setSelectionMode(SelectionMode selectionMode) { this.selectionMode = selectionMode; } } diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/ComponentListModel.java index aad379e..05ef7d4 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/ComponentListModel.java @@ -34,7 +34,7 @@ public final class ComponentListModel implements Iterable, Serializable { */ public boolean add(E e) { if (componentList != null) { - componentList.add(e); + componentList.addElement(e); componentList.revalidate(); } return elements.add(e); From 7dfeab58354d5d5508a09cdb43cb8ca6e4a9a184 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Fri, 20 Mar 2020 18:32:57 +0100 Subject: [PATCH 279/474] Adjusted ChatWindow and ContactsChooserDialog to new interface --- .../envoy/client/ui/container/ChatWindow.java | 10 ++-- .../ui/container/ContactsChooserDialog.java | 5 +- .../envoy/client/ui/list/ComponentList.java | 48 +++++++++++++++++-- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index a41a465..7d883c2 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -25,6 +25,7 @@ import envoy.client.net.WriteProxy; import envoy.client.ui.ContextMenu; import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; +import envoy.client.ui.list.ComponentList.SelectionMode; import envoy.client.ui.list.ComponentListModel; import envoy.client.ui.primary.PrimaryButton; import envoy.client.ui.primary.PrimaryScrollPane; @@ -125,18 +126,21 @@ public class ChatWindow extends JFrame { contentPane.setLayout(gbl_contentPane); messageList.setBorder(new EmptyBorder(space, space, space, space)); + messageList.setSelectionMode(SelectionMode.SINGLE); Map commands = new HashMap<>() { private static final long serialVersionUID = -2755235774946990126L; { put("forward selected message", - evt -> forwardMessageToMultipleUsers(messageList.getSelection().get(0), - ContactsChooserDialog.showForwardingDialog("Forward selected message to", messageList.getSelection().get(0), client))); + evt -> forwardMessageToMultipleUsers(messageList + .getSingleSelectedElement(), + ContactsChooserDialog + .showForwardingDialog("Forward selected message to", messageList.getSingleSelectedElement(), client))); put("copy", evt -> { // TODO should be enhanced to allow also copying of message attachments, // especially pictures - StringSelection copy = new StringSelection(messageList.getSelection().get(0).getText()); + StringSelection copy = new StringSelection(messageList.getSingleSelectedElement().getText()); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); }); // TODO insert implementation to edit and delete messages diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java index b85f9a8..467d43f 100644 --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -15,6 +15,7 @@ import envoy.client.data.Settings; import envoy.client.net.Client; import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; +import envoy.client.ui.list.ComponentList.SelectionMode; import envoy.client.ui.list.ComponentListModel; import envoy.client.ui.renderer.MessageListRenderer; import envoy.client.ui.renderer.UserComponentListRenderer; @@ -69,7 +70,7 @@ public class ContactsChooserDialog extends JDialog { dialog.getContentPanel() .add(new MessageListRenderer(client.getSender().getId()).getListCellComponent(null, message, false), BorderLayout.NORTH); List results = new ArrayList<>(); - dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelection()); dialog.dispose(); }); + dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelectedElements()); dialog.dispose(); }); ComponentListModel contactListModel = dialog.getContactList().getModel(); client.getContacts().getContacts().forEach(user -> contactListModel.add(user)); dialog.setVisible(true); @@ -82,7 +83,7 @@ public class ContactsChooserDialog extends JDialog { * @since Envoy v0.1-beta */ private ContactsChooserDialog() { - contactList.enableMultipleSelection(); + contactList.setSelectionMode(SelectionMode.MULTIPLE); // setBounds(100, 100, 450, 300); setModal(true); getContentPane().setLayout(new BorderLayout()); diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 2cac513..199946d 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -30,8 +30,26 @@ public class ComponentList extends JPanel { private static final long serialVersionUID = 1759644503942876737L; + /** + * Defines the possible modes of selection that can be performed by the user + * + * @since Envoy v0.1-beta + */ public static enum SelectionMode { - NONE, SINGLE, MULTIPLE + /** + * Selection is completely ignored. + */ + NONE, + + /** + * Only a single element can be selected. + */ + SINGLE, + + /** + * Multiple elements can be selected regardless of their position. + */ + MULTIPLE } /** @@ -202,6 +220,30 @@ public class ComponentList extends JPanel { */ public Set getSelection() { return selection; } + /** + * @return a set of all selected elements + * @since Envoy v0.1-beta + */ + public Set getSelectedElements() { + var selectedElements = new HashSet(); + selection.forEach(i -> selectedElements.add(model.get(i))); + return selectedElements; + } + + /** + * @return the index of an arbitrary selected element + * @throws java.util.NoSuchElementException if no selection is present + * @since Envoy v0.1-beta + */ + public int getSingleSelection() { return selection.iterator().next(); } + + /** + * @return an arbitrary selected element + * @throws java.util.NoSuchElementException if no selection is present + * @since Envoy v0.1-beta + */ + public E getSingleSelectedElement() { return model.get(getSingleSelection()); } + /** * @return the model * @since Envoy v0.1-beta @@ -221,13 +263,13 @@ public class ComponentList extends JPanel { public void setRenderer(ComponentListCellRenderer renderer) { this.renderer = renderer; } /** - * @return the selectionMode + * @return the selection mode * @since Envoy v0.1-beta */ public SelectionMode getSelectionMode() { return selectionMode; } /** - * @param selectionMode the selectionMode to set + * @param selectionMode the selection mode to set * @since Envoy v0.1-beta */ public void setSelectionMode(SelectionMode selectionMode) { this.selectionMode = selectionMode; } From bc30e5cb38d893826ed6bf1df170c5c6ecda8bee Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Mar 2020 13:20:45 +0100 Subject: [PATCH 280/474] Extracted MessageComponent from MessageListRenderer --- .../java/envoy/client/ui/ContextMenu.java | 11 +- .../envoy/client/ui/MessageComponent.java | 120 ++++++++++++++++++ .../envoy/client/ui/container/ChatWindow.java | 11 +- .../ui/container/ContactsChooserDialog.java | 2 +- .../envoy/client/ui/list/ComponentList.java | 23 +++- .../ui/renderer/MessageListRenderer.java | 104 +-------------- 6 files changed, 155 insertions(+), 116 deletions(-) create mode 100644 src/main/java/envoy/client/ui/MessageComponent.java diff --git a/src/main/java/envoy/client/ui/ContextMenu.java b/src/main/java/envoy/client/ui/ContextMenu.java index 1ba5d14..ff19ac8 100644 --- a/src/main/java/envoy/client/ui/ContextMenu.java +++ b/src/main/java/envoy/client/ui/ContextMenu.java @@ -50,7 +50,6 @@ public class ContextMenu extends JPopupMenu { private ButtonGroup radioButtonGroup = new ButtonGroup(); private boolean built = false; - private boolean visible = false; /** * @param parent the component which will call this @@ -110,8 +109,10 @@ public class ContextMenu extends JPopupMenu { if (mnemonics.containsKey(text)) item.setMnemonic(mnemonics.get(text)); add(item); }); - getInvoker().addMouseListener(getShowingListener()); - built = true; + if (getInvoker() != null) { + getInvoker().addMouseListener(getShowingListener()); + built = true; + } return this; } @@ -138,10 +139,8 @@ public class ContextMenu extends JPopupMenu { if (!built) build(); if (e.isPopupTrigger()) { // hides the menu if already visible - visible = !visible; - if (visible) show(e.getComponent(), e.getX(), e.getY()); + if (!isVisible()) show(e.getComponent(), e.getX(), e.getY()); else setVisible(false); - } } }; diff --git a/src/main/java/envoy/client/ui/MessageComponent.java b/src/main/java/envoy/client/ui/MessageComponent.java new file mode 100644 index 0000000..045e725 --- /dev/null +++ b/src/main/java/envoy/client/ui/MessageComponent.java @@ -0,0 +1,120 @@ +package envoy.client.ui; + +import java.awt.*; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.EnumMap; + +import javax.swing.*; + +import envoy.client.data.Settings; +import envoy.client.ui.list.ComponentList; +import envoy.data.Message; +import envoy.data.Message.MessageStatus; + +/** + * Project: envoy-client + * File: MessageComponent.java + * Created: 21.03.2020 + * + * @author Kai S. K. Engelbart + * @since Envoy v0.1-beta + */ +public class MessageComponent extends JPanel { + + private static final long serialVersionUID = 103920706139926996L; + + private static EnumMap statusIcons; + private static ImageIcon forwardIcon; + + static { + try { + statusIcons = IconUtil.loadByEnum(MessageStatus.class, 16); + forwardIcon = IconUtil.load("/icons/forward.png", 16); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public MessageComponent(ComponentList list, Message message, boolean isSelected, long senderId) { + this(list.getMaximumSize().width, message, isSelected, senderId); + } + + public MessageComponent(int width, Message message, boolean isSelected, long senderId) { + final var theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + final int padding = (int) (width * 0.35); + + GridBagLayout gbl_panel = new GridBagLayout(); + gbl_panel.columnWidths = new int[] { 1, 1 }; + gbl_panel.rowHeights = new int[] { 1, 1 }; + gbl_panel.columnWeights = new double[] { 1, 1 }; + gbl_panel.rowWeights = new double[] { 1, 1 }; + + setLayout(gbl_panel); + setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); + + // Date Label - The Label that displays the creation date of a message + var dateLabel = new JLabel(new SimpleDateFormat("dd.MM.yyyy HH:mm").format(message.getCreationDate())); + dateLabel.setForeground(theme.getDateColor()); + dateLabel.setAlignmentX(1f); + dateLabel.setFont(new Font("Arial", Font.PLAIN, 12)); + dateLabel.setPreferredSize(dateLabel.getPreferredSize()); + + var gbc_dateLabel = new GridBagConstraints(); + gbc_dateLabel.fill = GridBagConstraints.BOTH; + gbc_dateLabel.gridx = 0; + gbc_dateLabel.gridy = 0; + add(dateLabel, gbc_dateLabel); + + // Message area - The JTextArea that displays the text content of a message. + var messageTextArea = new JTextArea(message.getText()); + messageTextArea.setLineWrap(true); + messageTextArea.setWrapStyleWord(true); + messageTextArea.setForeground(theme.getMessageTextColor()); + messageTextArea.setAlignmentX(0.5f); + messageTextArea.setBackground(theme.getCellColor()); + messageTextArea.setEditable(false); + var font = new Font("Arial", Font.PLAIN, 14); + messageTextArea.setFont(font); + messageTextArea.setSize(width - padding - 16, 10); + + var gbc_messageTextArea = new GridBagConstraints(); + gbc_messageTextArea.fill = GridBagConstraints.HORIZONTAL; + gbc_messageTextArea.gridx = 0; + gbc_messageTextArea.gridy = 1; + add(messageTextArea, gbc_messageTextArea); + + // Status Label - displays the status of the message + var statusLabel = new JLabel(statusIcons.get(message.getStatus())); + + var gbc_statusLabel = new GridBagConstraints(); + gbc_statusLabel.gridx = 1; + gbc_statusLabel.gridy = 1; + add(statusLabel, gbc_statusLabel); + + // Forwarding + if (message.isForwarded()) { + var forwardLabel = new JLabel("Forwarded", forwardIcon, SwingConstants.CENTER); + forwardLabel.setBackground(getBackground()); + forwardLabel.setForeground(Color.lightGray); + + var gbc_forwardLabel = new GridBagConstraints(); + gbc_forwardLabel.fill = GridBagConstraints.BOTH; + gbc_forwardLabel.gridx = 1; + gbc_forwardLabel.gridy = 0; + add(forwardLabel, gbc_forwardLabel); + } + + // Define an etched border and some space to the messages below + var ours = senderId == message.getSenderId(); + setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder(0, ours ? padding : 10, 10, ours ? 0 : padding), + BorderFactory.createEtchedBorder())); + + var size = new Dimension(width - 50, getPreferredSize().height); + + setPreferredSize(size); + setMinimumSize(size); + setMaximumSize(size); + } +} diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index 7d883c2..808a4f7 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -125,16 +125,14 @@ public class ChatWindow extends JFrame { gbl_contentPane.rowWeights = new double[] { 0.03, 0.001, 1.0, 0.005 }; contentPane.setLayout(gbl_contentPane); - messageList.setBorder(new EmptyBorder(space, space, space, space)); - messageList.setSelectionMode(SelectionMode.SINGLE); + // ContextMenu Map commands = new HashMap<>() { private static final long serialVersionUID = -2755235774946990126L; { put("forward selected message", - evt -> forwardMessageToMultipleUsers(messageList - .getSingleSelectedElement(), + evt -> forwardMessageToMultipleUsers(messageList.getSingleSelectedElement(), ContactsChooserDialog .showForwardingDialog("Forward selected message to", messageList.getSingleSelectedElement(), client))); put("copy", evt -> { @@ -151,6 +149,11 @@ public class ChatWindow extends JFrame { }; contextMenu = new ContextMenu(null, messageList, commands, null, null).build(); + messageList.setBorder(new EmptyBorder(space, space, space, space)); + messageList.setSelectionMode(SelectionMode.SINGLE); + messageList.setSelectionListener((list, comp) -> + contextMenu.show(comp, 0, 0)); + scrollPane.setViewportView(messageList); scrollPane.addComponentListener(new ComponentAdapter() { diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java index 467d43f..3add91a 100644 --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -76,7 +76,7 @@ public class ContactsChooserDialog extends JDialog { dialog.setVisible(true); dialog.repaint(); dialog.revalidate(); - return results.size() > 0 ? results : null; + return results; } /** diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 199946d..a4b4953 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -5,6 +5,7 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.HashSet; import java.util.Set; +import java.util.function.BiConsumer; import javax.swing.*; @@ -23,10 +24,11 @@ import javax.swing.*; */ public class ComponentList extends JPanel { - private ComponentListModel model; - private ComponentListCellRenderer renderer; - private SelectionMode selectionMode = SelectionMode.NONE; - private Set selection = new HashSet<>(); + private ComponentListModel model; + private ComponentListCellRenderer renderer; + private SelectionMode selectionMode = SelectionMode.NONE; + private Set selection = new HashSet<>(); + private BiConsumer, JComponent> selectionListener; private static final long serialVersionUID = 1759644503942876737L; @@ -142,6 +144,9 @@ public class ComponentList extends JPanel { // Update element updateElement(index, true); + + // Trigger selection listener + if (selectionListener != null) selectionListener.accept(this, (JComponent) getComponents()[index]); } } @@ -273,4 +278,14 @@ public class ComponentList extends JPanel { * @since Envoy v0.1-beta */ public void setSelectionMode(SelectionMode selectionMode) { this.selectionMode = selectionMode; } + + /** + * @return the selectionListener + */ + public BiConsumer, JComponent> getSelectionListener() { return selectionListener; } + + /** + * @param selectionListener the selectionListener to set + */ + public void setSelectionListener(BiConsumer, JComponent> selectionListener) { this.selectionListener = selectionListener; } } diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java index 27a5a0d..a3c20bd 100644 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java @@ -1,19 +1,11 @@ package envoy.client.ui.renderer; -import java.awt.*; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.EnumMap; +import javax.swing.JPanel; -import javax.swing.*; - -import envoy.client.data.Settings; -import envoy.client.ui.Color; -import envoy.client.ui.IconUtil; +import envoy.client.ui.MessageComponent; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentListCellRenderer; import envoy.data.Message; -import envoy.data.Message.MessageStatus; /** * Defines how a message is displayed.
@@ -29,18 +21,6 @@ import envoy.data.Message.MessageStatus; */ public class MessageListRenderer implements ComponentListCellRenderer { - private static EnumMap statusIcons; - private static ImageIcon forwardIcon; - - static { - try { - statusIcons = IconUtil.loadByEnum(MessageStatus.class, 16); - forwardIcon = IconUtil.load("/icons/forward.png", 16); - } catch (IOException e) { - e.printStackTrace(); - } - } - private final long senderId; /** @@ -57,84 +37,6 @@ public class MessageListRenderer implements ComponentListCellRenderer { @Override public JPanel getListCellComponent(ComponentList list, Message message, boolean isSelected) { - final var theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - - // Panel - final var panel = new JPanel(); - final int padding = (int) (list.getWidth() * 0.35); - - GridBagLayout gbl_panel = new GridBagLayout(); - gbl_panel.columnWidths = new int[] { 1, 1 }; - gbl_panel.rowHeights = new int[] { 1, 1 }; - gbl_panel.columnWeights = new double[] { 1, 1 }; - gbl_panel.rowWeights = new double[] { 1, 1 }; - - panel.setLayout(gbl_panel); - panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); - - // Date Label - The Label that displays the creation date of a message - var dateLabel = new JLabel(new SimpleDateFormat("dd.MM.yyyy HH:mm").format(message.getCreationDate())); - dateLabel.setForeground(theme.getDateColor()); - dateLabel.setAlignmentX(1f); - dateLabel.setFont(new Font("Arial", Font.PLAIN, 12)); - dateLabel.setPreferredSize(dateLabel.getPreferredSize()); - - var gbc_dateLabel = new GridBagConstraints(); - gbc_dateLabel.fill = GridBagConstraints.BOTH; - gbc_dateLabel.gridx = 0; - gbc_dateLabel.gridy = 0; - panel.add(dateLabel, gbc_dateLabel); - - // Message area - The JTextArea that displays the text content of a message. - var messageTextArea = new JTextArea(message.getText()); - messageTextArea.setLineWrap(true); - messageTextArea.setWrapStyleWord(true); - messageTextArea.setForeground(theme.getMessageTextColor()); - messageTextArea.setAlignmentX(0.5f); - messageTextArea.setBackground(theme.getCellColor()); - messageTextArea.setEditable(false); - var font = new Font("Arial", Font.PLAIN, 14); - messageTextArea.setFont(font); - messageTextArea.setSize(list.getMaximumSize().width - padding - 16, 10); - - var gbc_messageTextArea = new GridBagConstraints(); - gbc_messageTextArea.fill = GridBagConstraints.HORIZONTAL; - gbc_messageTextArea.gridx = 0; - gbc_messageTextArea.gridy = 1; - panel.add(messageTextArea, gbc_messageTextArea); - - // Status Label - displays the status of the message - var statusLabel = new JLabel(statusIcons.get(message.getStatus())); - - var gbc_statusLabel = new GridBagConstraints(); - gbc_statusLabel.gridx = 1; - gbc_statusLabel.gridy = 1; - panel.add(statusLabel, gbc_statusLabel); - - // Forwarding - if (message.isForwarded()) { - var forwardLabel = new JLabel("Forwarded", forwardIcon, SwingConstants.CENTER); - forwardLabel.setBackground(panel.getBackground()); - forwardLabel.setForeground(Color.lightGray); - - var gbc_forwardLabel = new GridBagConstraints(); - gbc_forwardLabel.fill = GridBagConstraints.BOTH; - gbc_forwardLabel.gridx = 1; - gbc_forwardLabel.gridy = 0; - panel.add(forwardLabel, gbc_forwardLabel); - } - - // Define an etched border and some space to the messages below - var ours = senderId == message.getSenderId(); - panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, ours ? padding : 0, 10, ours ? 0 : padding), - BorderFactory.createEtchedBorder())); - - var size = new Dimension(list.getMaximumSize().width - 50, panel.getPreferredSize().height); - - panel.setPreferredSize(size); - panel.setMinimumSize(size); - panel.setMaximumSize(size); - - return panel; + return new MessageComponent(list, message, isSelected, senderId); } } From 2eefaaf8620c2239977652efbe68ec028c097930 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 21 Mar 2020 16:10:59 +0100 Subject: [PATCH 281/474] Revised the rendering and selection mechanism in ComponentList --- src/main/java/envoy/client/data/Chat.java | 6 +- src/main/java/envoy/client/data/Settings.java | 10 +- ...derer.java => ContactSearchComponent.java} | 51 +++--- .../envoy/client/ui/MessageComponent.java | 10 +- .../java/envoy/client/ui/UserComponent.java | 62 +++++++ .../envoy/client/ui/container/ChatWindow.java | 37 ++-- .../ui/container/ContactsChooserDialog.java | 22 +-- .../client/ui/container/LoginDialog.java | 2 +- .../envoy/client/ui/list/ComponentList.java | 165 +++++++----------- .../{ComponentListModel.java => Model.java} | 6 +- ...entListCellRenderer.java => Renderer.java} | 7 +- .../client/ui/list/SelectionHandler.java | 27 +++ .../client/ui/primary/PrimaryScrollBar.java | 11 +- .../ui/primary/PrimaryToggleSwitch.java | 2 +- .../ui/renderer/MessageListRenderer.java | 42 ----- .../renderer/UserComponentListRenderer.java | 70 -------- .../client/ui/renderer/UserListRenderer.java | 2 +- .../ui/settings/GeneralSettingsPanel.java | 2 +- .../client/ui/settings/NewThemeScreen.java | 2 +- .../client/ui/settings/SettingsScreen.java | 2 +- .../ui/settings/ThemeCustomizationPanel.java | 11 +- 21 files changed, 242 insertions(+), 307 deletions(-) rename src/main/java/envoy/client/ui/{renderer/ContactsSearchRenderer.java => ContactSearchComponent.java} (51%) create mode 100644 src/main/java/envoy/client/ui/UserComponent.java rename src/main/java/envoy/client/ui/list/{ComponentListModel.java => Model.java} (93%) rename src/main/java/envoy/client/ui/list/{ComponentListCellRenderer.java => Renderer.java} (86%) create mode 100644 src/main/java/envoy/client/ui/list/SelectionHandler.java delete mode 100644 src/main/java/envoy/client/ui/renderer/MessageListRenderer.java delete mode 100644 src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java diff --git a/src/main/java/envoy/client/data/Chat.java b/src/main/java/envoy/client/data/Chat.java index 30b6bc6..dadeaaa 100644 --- a/src/main/java/envoy/client/data/Chat.java +++ b/src/main/java/envoy/client/data/Chat.java @@ -4,7 +4,7 @@ import java.io.IOException; import java.io.Serializable; import envoy.client.net.WriteProxy; -import envoy.client.ui.list.ComponentListModel; +import envoy.client.ui.list.Model; import envoy.data.Message; import envoy.data.Message.MessageStatus; import envoy.data.User; @@ -28,7 +28,7 @@ public class Chat implements Serializable { private static final long serialVersionUID = -7751248474547242056L; private final User recipient; - private final ComponentListModel model = new ComponentListModel<>(); + private final Model model = new Model<>(); /** * Provides the list of messages that the recipient receives.
@@ -80,7 +80,7 @@ public class Chat implements Serializable { * @return all messages in the current chat * @since Envoy v0.1-alpha */ - public ComponentListModel getModel() { return model; } + public Model getModel() { return model; } /** * @return the recipient of a message diff --git a/src/main/java/envoy/client/data/Settings.java b/src/main/java/envoy/client/data/Settings.java index 89dea67..fd0170c 100644 --- a/src/main/java/envoy/client/data/Settings.java +++ b/src/main/java/envoy/client/data/Settings.java @@ -112,13 +112,19 @@ public class Settings { * @param theme the {@link Theme} to add * @since Envoy v0.2-alpha */ - public void addNewThemeToMap(Theme theme) { settings.getThemes().put(theme.getThemeName(), theme); } + public void addNewThemeToMap(Theme theme) { getThemes().put(theme.getThemeName(), theme); } /** * @return the name of the currently active {@link Theme} * @since Envoy v0.2-alpha */ - public String getCurrentTheme() { return (String) items.get("currentTheme").get(); } + public String getCurrentThemeName() { return (String) items.get("currentTheme").get(); } + + /** + * @return the currently active {@link Theme} + * @since Envoy v0.1-beta + */ + public Theme getCurrentTheme() { return getTheme(getCurrentThemeName()); } /** * Sets the name of the current {@link Theme}. diff --git a/src/main/java/envoy/client/ui/renderer/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactSearchComponent.java similarity index 51% rename from src/main/java/envoy/client/ui/renderer/ContactsSearchRenderer.java rename to src/main/java/envoy/client/ui/ContactSearchComponent.java index 60a0ef2..39ae50b 100644 --- a/src/main/java/envoy/client/ui/renderer/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/ContactSearchComponent.java @@ -1,4 +1,4 @@ -package envoy.client.ui.renderer; +package envoy.client.ui; import java.awt.Component; import java.awt.Dimension; @@ -8,45 +8,36 @@ import javax.swing.*; import envoy.client.data.Settings; import envoy.client.event.SendEvent; -import envoy.client.ui.Color; import envoy.client.ui.list.ComponentList; -import envoy.client.ui.list.ComponentListCellRenderer; import envoy.client.ui.primary.PrimaryButton; import envoy.data.User; import envoy.event.ContactOperationEvent; import envoy.event.EventBus; /** - * Defines how a contact is displayed.
- *
- * Project: envoy-client
- * File: ContactsSearchRenderer.java
- * Created: 08.02.2020
+ * Project: envoy-client + * File: ContactSearchComponent.java + * Created: 21.03.2020 * - * @author Maximilian Käfer * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy v0.1-beta */ -public class ContactsSearchRenderer implements ComponentListCellRenderer { +public class ContactSearchComponent extends JComponent { - @Override - public JComponent getListCellComponent(ComponentList list, User user, boolean isSelected) { - final JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); - if (isSelected) { - panel.setBackground(Color.DARK_GRAY); - panel.setForeground(Color.RED); - } else { - panel.setBackground(list.getBackground()); - panel.setForeground(list.getForeground()); - } + private static final long serialVersionUID = 3166795412575239455L; + + public ContactSearchComponent(ComponentList list, User user) { + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + + setBackground(list.getBackground()); + setForeground(list.getForeground()); JLabel display = new JLabel(user.getName()); - display.setForeground(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageTextColor()); + display.setForeground(Settings.getInstance().getCurrentTheme().getMessageTextColor()); display.setAlignmentX(Component.LEFT_ALIGNMENT); display.setAlignmentY(Component.CENTER_ALIGNMENT); display.setFont(new Font("Arial", Font.PLAIN, 16)); - panel.add(display); + add(display); PrimaryButton add = new PrimaryButton("+"); add.setFont(new Font("Arial", Font.PLAIN, 19)); @@ -63,17 +54,15 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { EventBus.getInstance().dispatch(new SendEvent(contactsOperationEvent)); }); - panel.add(add); + add(add); // Define some space to the messages below - panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0), BorderFactory.createEtchedBorder())); + setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0), BorderFactory.createEtchedBorder())); // Define a maximum height of 50px Dimension size = new Dimension(435, 50); - panel.setMaximumSize(size); - panel.setMinimumSize(size); - panel.setPreferredSize(size); - - return panel; + setMaximumSize(size); + setMinimumSize(size); + setPreferredSize(size); } } diff --git a/src/main/java/envoy/client/ui/MessageComponent.java b/src/main/java/envoy/client/ui/MessageComponent.java index 045e725..a4a83a0 100644 --- a/src/main/java/envoy/client/ui/MessageComponent.java +++ b/src/main/java/envoy/client/ui/MessageComponent.java @@ -36,12 +36,12 @@ public class MessageComponent extends JPanel { } } - public MessageComponent(ComponentList list, Message message, boolean isSelected, long senderId) { - this(list.getMaximumSize().width, message, isSelected, senderId); + public MessageComponent(ComponentList list, Message message, long senderId) { + this(list.getMaximumSize().width, message, senderId); } - public MessageComponent(int width, Message message, boolean isSelected, long senderId) { - final var theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + public MessageComponent(int width, Message message, long senderId) { + final var theme = Settings.getInstance().getCurrentTheme(); final int padding = (int) (width * 0.35); GridBagLayout gbl_panel = new GridBagLayout(); @@ -51,7 +51,7 @@ public class MessageComponent extends JPanel { gbl_panel.rowWeights = new double[] { 1, 1 }; setLayout(gbl_panel); - setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); + setBackground(theme.getCellColor()); // Date Label - The Label that displays the creation date of a message var dateLabel = new JLabel(new SimpleDateFormat("dd.MM.yyyy HH:mm").format(message.getCreationDate())); diff --git a/src/main/java/envoy/client/ui/UserComponent.java b/src/main/java/envoy/client/ui/UserComponent.java new file mode 100644 index 0000000..7fd4392 --- /dev/null +++ b/src/main/java/envoy/client/ui/UserComponent.java @@ -0,0 +1,62 @@ +package envoy.client.ui; + +import java.awt.BorderLayout; +import java.awt.Dimension; + +import javax.swing.JComponent; +import javax.swing.JLabel; + +import envoy.client.data.Settings; +import envoy.client.ui.list.ComponentList; +import envoy.data.User; +import envoy.data.User.UserStatus; + +/** + * Project: envoy-client + * File: UserComponent.java + * Created: 21.03.2020 + * + * @author Kai S. K. Engelbart + * @since Envoy v0.1-beta + */ +public class UserComponent extends JComponent { + + private static final long serialVersionUID = 8450602172939729585L; + + public UserComponent(ComponentList list, User user) { + final Theme theme = Settings.getInstance().getCurrentTheme(); + + setLayout(new BorderLayout()); + + // Panel background + setBackground(theme.getCellColor()); + setOpaque(true); + setPreferredSize(new Dimension(100, 35)); + + // TODO add profile picture support in BorderLayout.West + + JLabel username = new JLabel(user.getName()); + username.setForeground(theme.getUserNameColor()); + add(username, BorderLayout.CENTER); + + final UserStatus status = user.getStatus(); + JLabel statusLabel = new JLabel(status.toString()); + Color foreground; + switch (status) { + case AWAY: + foreground = Color.yellow; + break; + case BUSY: + foreground = Color.blue; + break; + case ONLINE: + foreground = Color.green; + break; + default: + foreground = Color.lightGray; + break; + } + statusLabel.setForeground(foreground); + add(statusLabel, BorderLayout.NORTH); + } +} diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index 808a4f7..41e9614 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -22,16 +22,13 @@ import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.net.Client; import envoy.client.net.WriteProxy; -import envoy.client.ui.ContextMenu; -import envoy.client.ui.Theme; +import envoy.client.ui.*; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentList.SelectionMode; -import envoy.client.ui.list.ComponentListModel; +import envoy.client.ui.list.Model; import envoy.client.ui.primary.PrimaryButton; import envoy.client.ui.primary.PrimaryScrollPane; import envoy.client.ui.primary.PrimaryTextArea; -import envoy.client.ui.renderer.ContactsSearchRenderer; -import envoy.client.ui.renderer.MessageListRenderer; import envoy.client.ui.renderer.UserListRenderer; import envoy.client.ui.settings.SettingsScreen; import envoy.data.Message; @@ -54,8 +51,7 @@ import envoy.util.EnvoyLog; public class ChatWindow extends JFrame { /** - * This int defines the maximum amount of chars allowed per message. Currently - * set at 200. + * This integer defines the maximum amount of chars allowed per message. * * @since Envoy 0.1-beta */ @@ -77,7 +73,6 @@ public class ChatWindow extends JFrame { private JTextPane textPane = new JTextPane(); private PrimaryButton postButton = new PrimaryButton("Post"); private PrimaryButton settingsButton = new PrimaryButton("Settings"); - @SuppressWarnings("unused") private JPopupMenu contextMenu; // Contacts Header @@ -86,13 +81,12 @@ public class ChatWindow extends JFrame { private PrimaryButton addContact = new PrimaryButton("+"); // Search Contacts - private final JPanel searchPane = new JPanel(); - private final PrimaryButton cancelButton = new PrimaryButton("x"); - private final PrimaryTextArea searchField = new PrimaryTextArea(space); - private final PrimaryScrollPane scrollForPossibleContacts = new PrimaryScrollPane(); - private final ContactsSearchRenderer contactRenderer = new ContactsSearchRenderer(); - private final ComponentListModel contactsModel = new ComponentListModel<>(); - private final ComponentList contactList = new ComponentList<>(contactRenderer); + private final JPanel searchPane = new JPanel(); + private final PrimaryButton cancelButton = new PrimaryButton("x"); + private final PrimaryTextArea searchField = new PrimaryTextArea(space); + private final PrimaryScrollPane scrollForPossibleContacts = new PrimaryScrollPane(); + private final Model contactsModel = new Model<>(); + private final ComponentList contactList = new ComponentList().setRenderer(ContactSearchComponent::new); private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class); @@ -151,8 +145,11 @@ public class ChatWindow extends JFrame { messageList.setBorder(new EmptyBorder(space, space, space, space)); messageList.setSelectionMode(SelectionMode.SINGLE); - messageList.setSelectionListener((list, comp) -> - contextMenu.show(comp, 0, 0)); + messageList.setSelectionHandler((message, comp, isSelected) -> { + final var theme = Settings.getInstance().getCurrentTheme(); + comp.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); + contextMenu.show(comp, 0, 0); + }); scrollPane.setViewportView(messageList); scrollPane.addComponentListener(new ComponentAdapter() { @@ -399,11 +396,11 @@ public class ChatWindow extends JFrame { gbc_addContact.gridy = 0; gbc_addContact.insets = insets; - addContact.addActionListener((evt) -> { drawContactSearch(gbc_searchPane); }); + addContact.addActionListener(evt -> drawContactSearch(gbc_searchPane)); contactsHeader.add(addContact, gbc_addContact); - applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + applyTheme(Settings.getInstance().getCurrentTheme()); contentPane.add(contactsHeader, gbc_contactsHeader); contentPane.revalidate(); @@ -648,7 +645,7 @@ public class ChatWindow extends JFrame { this.localDb = localDb; this.writeProxy = writeProxy; - messageList.setRenderer(new MessageListRenderer(client.getSender().getId())); + messageList.setRenderer((list, message) -> new MessageComponent(list, message, client.getSender().getId())); // Load users and chats new Thread(() -> { diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java index 3add91a..8171b82 100644 --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -14,11 +14,10 @@ import javax.swing.border.EmptyBorder; import envoy.client.data.Settings; import envoy.client.net.Client; import envoy.client.ui.Theme; +import envoy.client.ui.UserComponent; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentList.SelectionMode; -import envoy.client.ui.list.ComponentListModel; -import envoy.client.ui.renderer.MessageListRenderer; -import envoy.client.ui.renderer.UserComponentListRenderer; +import envoy.client.ui.list.Model; import envoy.data.Message; import envoy.data.User; @@ -36,11 +35,11 @@ public class ContactsChooserDialog extends JDialog { private static final long serialVersionUID = -5774558118579032256L; - private ComponentList contactList = new ComponentList<>(new UserComponentListRenderer()); + private ComponentList contactList = new ComponentList().setRenderer(UserComponent::new); private JButton okButton = new JButton("Ok"); private JButton cancelButton = new JButton("Cancel"); - private final Theme theme = Settings.getInstance().getTheme(Settings.getInstance().getCurrentTheme()); + private final Theme theme = Settings.getInstance().getCurrentTheme(); private final JPanel contentPanel = new JPanel(); @@ -67,11 +66,13 @@ public class ContactsChooserDialog extends JDialog { dialog.setTitle(title); dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE); dialog.addCancelButtonActionListener(e -> dialog.dispose()); - dialog.getContentPanel() - .add(new MessageListRenderer(client.getSender().getId()).getListCellComponent(null, message, false), BorderLayout.NORTH); + // dialog.getContentPanel() + // .add(new + // MessageListRenderer(client.getSender().getId()).getListCellComponent(null, + // message, false), BorderLayout.NORTH); List results = new ArrayList<>(); dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelectedElements()); dialog.dispose(); }); - ComponentListModel contactListModel = dialog.getContactList().getModel(); + Model contactListModel = dialog.getContactList().getModel(); client.getContacts().getContacts().forEach(user -> contactListModel.add(user)); dialog.setVisible(true); dialog.repaint(); @@ -84,7 +85,8 @@ public class ContactsChooserDialog extends JDialog { */ private ContactsChooserDialog() { contactList.setSelectionMode(SelectionMode.MULTIPLE); - // setBounds(100, 100, 450, 300); + contactList + .setSelectionHandler((user, comp, isSelected) -> comp.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor())); setModal(true); getContentPane().setLayout(new BorderLayout()); setBackground(theme.getBackgroundColor()); @@ -121,6 +123,4 @@ public class ContactsChooserDialog extends JDialog { private void addOkButtonActionListener(ActionListener l) { okButton.addActionListener(l); } private void addCancelButtonActionListener(ActionListener l) { cancelButton.addActionListener(l); } - - private JPanel getContentPanel() { return contentPanel; } } diff --git a/src/main/java/envoy/client/ui/container/LoginDialog.java b/src/main/java/envoy/client/ui/container/LoginDialog.java index 51d9817..8780358 100644 --- a/src/main/java/envoy/client/ui/container/LoginDialog.java +++ b/src/main/java/envoy/client/ui/container/LoginDialog.java @@ -291,7 +291,7 @@ public class LoginDialog extends JDialog { } private void setTheme() { - Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + Theme theme = Settings.getInstance().getCurrentTheme(); // Panels contentPanel.setBackground(theme.getBackgroundColor()); diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index a4b4953..44d98de 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -5,13 +5,12 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.HashSet; import java.util.Set; -import java.util.function.BiConsumer; import javax.swing.*; /** * Provides a vertical list layout of components provided in a - * {@link ComponentListModel}. Similar to {@link javax.swing.JList} but capable + * {@link Model}. Similar to {@link javax.swing.JList} but capable * of rendering {@link JPanel}s.
*
* Project: envoy-client
@@ -24,11 +23,11 @@ import javax.swing.*; */ public class ComponentList extends JPanel { - private ComponentListModel model; - private ComponentListCellRenderer renderer; - private SelectionMode selectionMode = SelectionMode.NONE; - private Set selection = new HashSet<>(); - private BiConsumer, JComponent> selectionListener; + private Model model; + private Renderer renderer; + private SelectionHandler selectionHandler; + private SelectionMode selectionMode = SelectionMode.NONE; + private Set selection = new HashSet<>(); private static final long serialVersionUID = 1759644503942876737L; @@ -55,64 +54,20 @@ public class ComponentList extends JPanel { } /** - * Initializes a default {@link ComponentList} without a model or a renderer. + * Creates an instance of {@link ComponentList}. * - * @since Envoy v0.1-beta + * @since Envoy v0.3-alpha */ public ComponentList() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); } - /** - * Creates an instance of {@link ComponentList}. - * - * @param renderer the list cell renderer used to display elements provided by - * the {@link ComponentListModel} - * @since Envoy v0.3-alpha - */ - public ComponentList(ComponentListCellRenderer renderer) { - this(); - setRenderer(renderer); - } - - /** - * Creates an instance of {@link ComponentList}. - * - * @param model the list model providing the list elements to render - * @param renderer the list cell renderer used to display elements provided by - * the {@link ComponentListModel} - * @since Envoy v0.3-alpha - */ - public ComponentList(ComponentListModel model, ComponentListCellRenderer renderer) { - this(renderer); - setModel(model); - } - - /** - * Sets the list model providing the list elements to render. The rendered - * components will be synchronized with the contents of the new model or removed - * if the new model is {@code null}. - * - * @param model the list model to set - * @since Envoy v0.3-alpha - */ - public void setModel(ComponentListModel model) { - - // Remove old model - if (this.model != null) this.model.setComponentList(null); - - // Synchronize with new model - this.model = model; - if (model != null) model.setComponentList(this); - synchronizeModel(); - } - /** * Removes all child components and then adds all components representing the - * elements of the {@link ComponentListModel}. + * elements of the {@link Model}. * * @since Envoy v0.3-alpha */ public void synchronizeModel() { - if (model != null && renderer != null) { + if (model != null) { removeAll(); model.forEach(this::addElement); revalidate(); @@ -127,10 +82,12 @@ public class ComponentList extends JPanel { * @since Envoy v0.1-beta */ public void selectElement(int index) { + final JComponent element = getComponent(index); + if (selection.contains(index)) { // Remove selection of element at index - updateElement(index, false); + if (selectionHandler != null) selectionHandler.selectionChanged(model.get(index), element, true); selection.remove(index); } else { @@ -143,10 +100,7 @@ public class ComponentList extends JPanel { selection.add(index); // Update element - updateElement(index, true); - - // Trigger selection listener - if (selectionListener != null) selectionListener.accept(this, (JComponent) getComponents()[index]); + if (selectionHandler != null) selectionHandler.selectionChanged(model.get(index), element, true); } } @@ -160,49 +114,25 @@ public class ComponentList extends JPanel { * @since Envoy v0.1-alpha */ public void clearSelection() { - selection.forEach(i -> updateElement(i, false)); + if (selectionHandler != null) selection.forEach(i -> selectionHandler.selectionChanged(model.get(i), getComponent(i), false)); selection.clear(); } /** * Adds an object to the list by rendering it with the current - * {@link ComponentListCellRenderer}. + * {@link Renderer}. * * @param elem the element to add * @since Envoy v0.3-alpha */ - void addElement(E elem) { addElement(elem, getComponentCount(), false); } - - /** - * Adds an object to the list by rendering it with the current - * {@link ComponentListRenderer}. If the renderer is {@code null}, no action is - * performed. - * - * @param elem the element to add - * @param index the index at which to add the element - * @param isSelected the selection state of the element - * @since Envoy v0.1-beta - */ - private void addElement(E elem, int index, boolean isSelected) { + void addElement(E elem) { if (renderer != null) { - final JComponent component = renderer.getListCellComponent(this, elem, isSelected); - component.addMouseListener(getSelectionListener(index)); - add(component, index); + final JComponent component = renderer.getListCellComponent(this, elem); + component.addMouseListener(getSelectionListener(getComponentCount())); + add(component, getComponentCount()); } } - /** - * Replaces a list element with a newly rendered instance of its contents. - * - * @param index the index of the element to update - * @param isSelected the selection state passed to the {@link ListCellRenderer} - * @since Envoy v0.1-beta - */ - private void updateElement(int index, boolean isSelected) { - remove(index); - addElement(model.get(index), index, isSelected); - } - /** * @param componentIndex the index of the list component to which the mouse * listener will be added @@ -219,6 +149,9 @@ public class ComponentList extends JPanel { }; } + @Override + public JComponent getComponent(int n) { return (JComponent) super.getComponent(n); } + /** * @return a set of all selected indices * @since Envoy v0.1-beta @@ -253,19 +186,45 @@ public class ComponentList extends JPanel { * @return the model * @since Envoy v0.1-beta */ - public ComponentListModel getModel() { return model; } + public Model getModel() { return model; } + + /** + * Sets the list model providing the list elements to render. The rendered + * components will be synchronized with the contents of the new model or removed + * if the new model is {@code null}. + * + * @param model the list model to set + * @return this component list + * @since Envoy v0.3-alpha + */ + public ComponentList setModel(Model model) { + + // Remove old model + if (this.model != null) this.model.setComponentList(null); + + // Synchronize with new model + this.model = model; + if (model != null) model.setComponentList(this); + synchronizeModel(); + + return this; + } /** * @return the renderer * @since Envoy v0.1-beta */ - public ComponentListCellRenderer getRenderer() { return renderer; } + public Renderer getRenderer() { return renderer; } /** * @param renderer the renderer to set + * @return this component list * @since Envoy v0.1-beta */ - public void setRenderer(ComponentListCellRenderer renderer) { this.renderer = renderer; } + public ComponentList setRenderer(Renderer renderer) { + this.renderer = renderer; + return this; + } /** * @return the selection mode @@ -274,18 +233,28 @@ public class ComponentList extends JPanel { public SelectionMode getSelectionMode() { return selectionMode; } /** + * Sets a new selection mode. The current selection will be cleared during this + * action. + * * @param selectionMode the selection mode to set + * @return this component list * @since Envoy v0.1-beta */ - public void setSelectionMode(SelectionMode selectionMode) { this.selectionMode = selectionMode; } + public ComponentList setSelectionMode(SelectionMode selectionMode) { + this.selectionMode = selectionMode; + clearSelection(); + return this; + } /** - * @return the selectionListener + * @return the selection handler + * @since Envoy v0.1-beta */ - public BiConsumer, JComponent> getSelectionListener() { return selectionListener; } + public SelectionHandler getSelectionHandler() { return selectionHandler; } /** - * @param selectionListener the selectionListener to set + * @param selectionHandler the selection handler to set + * @since Envoy v0.1-beta */ - public void setSelectionListener(BiConsumer, JComponent> selectionListener) { this.selectionListener = selectionListener; } + public void setSelectionHandler(SelectionHandler selectionHandler) { this.selectionHandler = selectionHandler; } } diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/Model.java similarity index 93% rename from src/main/java/envoy/client/ui/list/ComponentListModel.java rename to src/main/java/envoy/client/ui/list/Model.java index 05ef7d4..6dca5eb 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/Model.java @@ -9,19 +9,19 @@ import java.util.List; * Stores objects that will be displayed in a {@link ComponentList}.
*
* Project: envoy-client
- * File: ComponentListModel.java
+ * File: Model.java
* Created: 25.01.2020
* * @param the type of object displayed in this list * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ -public final class ComponentListModel implements Iterable, Serializable { +public final class Model implements Iterable, Serializable { private List elements = new ArrayList<>(); transient private ComponentList componentList; - private static final long serialVersionUID = 4815005915255497331L; + private static final long serialVersionUID = 0L; /** * Adds an element to this model and notifies the associated diff --git a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java b/src/main/java/envoy/client/ui/list/Renderer.java similarity index 86% rename from src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java rename to src/main/java/envoy/client/ui/list/Renderer.java index a8bdda6..58e6ad9 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java +++ b/src/main/java/envoy/client/ui/list/Renderer.java @@ -7,14 +7,15 @@ import javax.swing.JComponent; * that can be rendered.
*
* Project: envoy-client
- * File: ComponentListCellRenderer.java
+ * File: Renderer.java
* Created: 25.01.2020
* * @param the type of object displayed in this list * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ -public interface ComponentListCellRenderer { +@FunctionalInterface +public interface Renderer { /** * Provides a Swing component representing a list element. @@ -26,5 +27,5 @@ public interface ComponentListCellRenderer { * @return the component representing the list element * @since Envoy v0.3-alpha */ - JComponent getListCellComponent(ComponentList list, E value, boolean isSelected); + JComponent getListCellComponent(ComponentList list, E value); } diff --git a/src/main/java/envoy/client/ui/list/SelectionHandler.java b/src/main/java/envoy/client/ui/list/SelectionHandler.java new file mode 100644 index 0000000..b6ed40a --- /dev/null +++ b/src/main/java/envoy/client/ui/list/SelectionHandler.java @@ -0,0 +1,27 @@ +package envoy.client.ui.list; + +import javax.swing.JComponent; + +/** + * Handles the selection of elements in a {@link ComponentList}.
+ *
+ * Project: envoy-client + * File: SelectionHandler.java + * Created: 21.03.2020 + * + * @author Kai S. K. Engelbart + * @since Envoy v0.1-beta + */ +@FunctionalInterface +public interface SelectionHandler { + + /** + * Notifies the handler about a selection. + * + * @param element the selected element + * @param component the selected component + * @param isSelected contains the selection state + * @since Envoy v0.1-beta + */ + void selectionChanged(E element, JComponent component, boolean isSelected); +} diff --git a/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java index 7dd560e..59846fa 100644 --- a/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java @@ -1,11 +1,6 @@ package envoy.client.ui.primary; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.RenderingHints; +import java.awt.*; import javax.swing.JButton; import javax.swing.JComponent; @@ -98,11 +93,11 @@ public class PrimaryScrollBar extends BasicScrollBarUI { g2.setPaint(color); if (isVertical) { g2.fillRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); - g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); + g2.setPaint(Settings.getInstance().getCurrentTheme().getCellColor()); g2.drawRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); } else { g2.fillRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); - g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); + g2.setPaint(Settings.getInstance().getCurrentTheme().getCellColor()); g2.drawRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); } g2.dispose(); diff --git a/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java index 30ee098..fea465f 100644 --- a/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java @@ -52,7 +52,7 @@ public class PrimaryToggleSwitch extends JButton { g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY); g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25); - g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); + g.setColor(Settings.getInstance().getCurrentTheme().getInteractableBackgroundColor()); g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25); } } diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java deleted file mode 100644 index a3c20bd..0000000 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ /dev/null @@ -1,42 +0,0 @@ -package envoy.client.ui.renderer; - -import javax.swing.JPanel; - -import envoy.client.ui.MessageComponent; -import envoy.client.ui.list.ComponentList; -import envoy.client.ui.list.ComponentListCellRenderer; -import envoy.data.Message; - -/** - * Defines how a message is displayed.
- *
- * Project: envoy-client
- * File: MessageListRenderer.java
- * Created: 19 Oct 2019
- * - * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @author Leon Hofmeister - * @since Envoy v0.1-alpha - */ -public class MessageListRenderer implements ComponentListCellRenderer { - - private final long senderId; - - /** - * Initializes a message list renderer. Messages with the given sender ID will - * be aligned on the right side, while all other messages will be aligned on - * the left side - * - * @param senderId the sender ID of the messages to align on the right side - * @since Envoy v0.1-beta - */ - public MessageListRenderer(long senderId) { this.senderId = senderId; } - - // TODO: Handle message attachments - - @Override - public JPanel getListCellComponent(ComponentList list, Message message, boolean isSelected) { - return new MessageComponent(list, message, isSelected, senderId); - } -} diff --git a/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java b/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java deleted file mode 100644 index f19f17e..0000000 --- a/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java +++ /dev/null @@ -1,70 +0,0 @@ -package envoy.client.ui.renderer; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.io.Serializable; - -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JPanel; - -import envoy.client.data.Settings; -import envoy.client.ui.Color; -import envoy.client.ui.Theme; -import envoy.client.ui.list.ComponentList; -import envoy.client.ui.list.ComponentListCellRenderer; -import envoy.data.User; -import envoy.data.User.UserStatus; - -/** - * Project: envoy-client
- * File: UserComponentListRenderer.java
- * Created: 15 Mar 2020
- * - * @author Leon Hofmeister - * @since Envoy v0.1-beta - */ -public class UserComponentListRenderer implements ComponentListCellRenderer, Serializable { - - private static final long serialVersionUID = -2379244319112111284L; - - @Override - public JComponent getListCellComponent(ComponentList list, User user, boolean isSelected) { - final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - - final JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); - - // Panel background - panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); - panel.setOpaque(true); - panel.setPreferredSize(new Dimension(100, 35)); - - // TODO add profile picture support in BorderLayout.West - - JLabel username = new JLabel(user.getName()); - username.setForeground(theme.getUserNameColor()); - panel.add(username, BorderLayout.CENTER); - - final UserStatus status = user.getStatus(); - JLabel statusLabel = new JLabel(status.toString()); - Color foreground; - switch (status) { - case AWAY: - foreground = Color.yellow; - break; - case BUSY: - foreground = Color.blue; - break; - case ONLINE: - foreground = Color.green; - break; - default: - foreground = Color.lightGray; - break; - } - statusLabel.setForeground(foreground); - panel.add(statusLabel, BorderLayout.NORTH); - return panel; - } -} diff --git a/src/main/java/envoy/client/ui/renderer/UserListRenderer.java b/src/main/java/envoy/client/ui/renderer/UserListRenderer.java index 7f6bc0c..89435df 100644 --- a/src/main/java/envoy/client/ui/renderer/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/UserListRenderer.java @@ -46,7 +46,7 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { // Getting the UserNameColor of the current theme String textColor = null; - textColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor().toHex(); + textColor = Settings.getInstance().getCurrentTheme().getUserNameColor().toHex(); switch (status) { case ONLINE: setText(String diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index c85c048..fbc3952 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -43,7 +43,7 @@ public class GeneralSettingsPanel extends SettingsPanel { */ public GeneralSettingsPanel(SettingsScreen parent) { super(parent); - theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + theme = Settings.getInstance().getCurrentTheme(); setBackground(theme.getCellColor()); diff --git a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java index 4fdab10..906bb91 100644 --- a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java +++ b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java @@ -61,7 +61,7 @@ public class NewThemeScreen extends JDialog { setDimensions(true); setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + Theme theme = Settings.getInstance().getCurrentTheme(); getContentPane().setLayout(new BorderLayout()); standardPanel.setBackground(theme.getBackgroundColor()); diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index e1ae290..22a24a4 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -156,7 +156,7 @@ public class SettingsScreen extends JDialog { } // Apply current theme - applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + applyTheme(Settings.getInstance().getCurrentTheme()); // Respond to theme changes EventBus.getInstance().register(ThemeChangeEvent.class, evt -> applyTheme(evt.get())); diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 8772064..5408a05 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -38,8 +38,9 @@ public class ThemeCustomizationPanel extends SettingsPanel { private final Insets insets = new Insets(5, 5, 5, 5); - private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class); - private static final long serialVersionUID = -8697897390666456624L; + private static final Settings settings = Settings.getInstance(); + private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class); + private static final long serialVersionUID = -8697897390666456624L; /** * Initializes a {@link ThemeCustomizationPanel} that enables the user to change @@ -52,7 +53,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { */ public ThemeCustomizationPanel(SettingsScreen parent) { super(parent); - temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", settings.getCurrentTheme()); GridBagLayout gbl_themeLayout = new GridBagLayout(); @@ -63,7 +64,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { setLayout(gbl_themeLayout); - themes.setSelectedItem(Settings.getInstance().getCurrentTheme()); + themes.setSelectedItem(settings.getCurrentTheme()); GridBagConstraints gbc_themes = new GridBagConstraints(); gbc_themes.fill = GridBagConstraints.HORIZONTAL; @@ -83,7 +84,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.setLayout(gbl_colorCustomizations); - Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + Theme theme = settings.getCurrentTheme(); buildCustomizeElements(theme); GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); From 8c55f67eb0d3f005979e466ac853caeb7055aa32 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 21 Mar 2020 19:26:11 +0100 Subject: [PATCH 282/474] Fixed bug adding a line break when sending via enter * additionally merged full input of f/enhanced_component_list with the current working state of f/forward_messages: * implemented setting of colors (theming) for ContextMenu * renamed messageTextColor to textColor --- .../java/envoy/client/{ui => }/Startup.java | 5 +- src/main/java/envoy/client/ui/Theme.java | 9 +- .../envoy/client/ui/container/ChatWindow.java | 16 +- .../ui/container/ContactsChooserDialog.java | 10 +- .../client/ui/container/ContextMenu.java | 246 ++++++++++++++++++ .../client/ui/list/SelectionHandler.java | 7 +- .../ContactSearchComponent.java | 9 +- .../MessageComponent.java | 23 +- .../{ => list_component}/UserComponent.java | 13 +- .../ui/list_component/package-info.java | 14 + .../ui/settings/ThemeCustomizationPanel.java | 13 +- 11 files changed, 325 insertions(+), 40 deletions(-) rename src/main/java/envoy/client/{ui => }/Startup.java (98%) mode change 100644 => 100755 src/main/java/envoy/client/ui/Theme.java mode change 100644 => 100755 src/main/java/envoy/client/ui/container/ContactsChooserDialog.java create mode 100755 src/main/java/envoy/client/ui/container/ContextMenu.java rename src/main/java/envoy/client/ui/{ => list_component}/ContactSearchComponent.java (89%) rename src/main/java/envoy/client/ui/{ => list_component}/MessageComponent.java (84%) rename src/main/java/envoy/client/ui/{ => list_component}/UserComponent.java (83%) create mode 100644 src/main/java/envoy/client/ui/list_component/package-info.java mode change 100644 => 100755 src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/Startup.java similarity index 98% rename from src/main/java/envoy/client/ui/Startup.java rename to src/main/java/envoy/client/Startup.java index 5c03881..012b1e8 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/Startup.java @@ -1,4 +1,4 @@ -package envoy.client.ui; +package envoy.client; import java.awt.EventQueue; import java.io.File; @@ -15,6 +15,7 @@ import javax.swing.SwingUtilities; import envoy.client.data.*; import envoy.client.net.Client; import envoy.client.net.WriteProxy; +import envoy.client.ui.StatusTrayIcon; import envoy.client.ui.container.ChatWindow; import envoy.client.ui.container.LoginDialog; import envoy.data.Config; @@ -129,7 +130,7 @@ public class Startup { // Save all users to the local database and flush cache localDb.setUsers(client.getUsers()); writeProxy.flushCache(); - } else + } else // Set all contacts to offline mode localDb.getUsers().values().stream().filter(u -> u != localDb.getUser()).forEach(u -> u.setStatus(UserStatus.OFFLINE)); diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java old mode 100644 new mode 100755 index 2956882..9fb8726 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -29,7 +29,8 @@ public class Theme implements Serializable { * elements * @param interactableBackgroundColor the color of interactable background UI * elements - * @param messageColorChat the color of chat messages + * @param textColor the color normal text should be displayed + * in * @param dateColorChat the color of chat message metadata * @param selectionColor the section color * @param typingMessageColor the color of currently typed messages @@ -37,7 +38,7 @@ public class Theme implements Serializable { * @since Envoy v0.2-alpha */ public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, Color interactableBackgroundColor, - Color messageColorChat, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) { + Color textColor, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) { this.themeName = themeName; @@ -45,7 +46,7 @@ public class Theme implements Serializable { colors.put("cellColor", cellColor); colors.put("interactableForegroundColor", interactableForegroundColor); colors.put("interactableBackgroundColor", interactableBackgroundColor); - colors.put("messageColorChat", messageColorChat); + colors.put("textColor", textColor); colors.put("dateColorChat", dateColorChat); colors.put("selectionColor", selectionColor); colors.put("typingMessageColor", typingMessageColor); @@ -89,7 +90,7 @@ public class Theme implements Serializable { * displayed * @since Envoy v0.2-alpha */ - public Color getMessageTextColor() { return colors.get("messageColorChat"); } + public Color getTextColor() { return colors.get("textColor"); } /** * @return the {@link Color} in which the creation date of a message should be diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index 41e9614..6f16af4 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -22,10 +22,12 @@ import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.net.Client; import envoy.client.net.WriteProxy; -import envoy.client.ui.*; +import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentList.SelectionMode; import envoy.client.ui.list.Model; +import envoy.client.ui.list_component.ContactSearchComponent; +import envoy.client.ui.list_component.MessageComponent; import envoy.client.ui.primary.PrimaryButton; import envoy.client.ui.primary.PrimaryScrollPane; import envoy.client.ui.primary.PrimaryTextArea; @@ -490,7 +492,7 @@ public class ChatWindow extends JFrame { contentPane.setBackground(theme.getBackgroundColor()); contentPane.setForeground(theme.getUserNameColor()); // messageList - messageList.setForeground(theme.getMessageTextColor()); + messageList.setForeground(theme.getTextColor()); messageList.setBackground(theme.getCellColor()); // scrollPane scrollPane.applyTheme(theme); @@ -525,7 +527,7 @@ public class ChatWindow extends JFrame { searchField.setForeground(theme.getUserNameColor()); cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor()); - contactList.setForeground(theme.getMessageTextColor()); + contactList.setForeground(theme.getTextColor()); contactList.setBackground(theme.getCellColor()); scrollForPossibleContacts.applyTheme(theme); } @@ -540,11 +542,15 @@ public class ChatWindow extends JFrame { JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); return; } + String text = messageEnterTextArea.getText().trim(); + if (!text.isEmpty()) checkMessageTextLength(); + // delete final line break, if present (especially if "Enter" is used to send + // the message) + if (text.endsWith(System.getProperty("line.separator"))) text = text.substring(0, text.lastIndexOf(System.getProperty("line.separator"))); - if (!messageEnterTextArea.getText().isEmpty()) checkMessageTextLength(); // Create message final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator()) - .setText(messageEnterTextArea.getText()) + .setText(text) .build(); sendMessage(message); // Clear text field diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java old mode 100644 new mode 100755 index 8171b82..5677e7d --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -14,7 +14,6 @@ import javax.swing.border.EmptyBorder; import envoy.client.data.Settings; import envoy.client.net.Client; import envoy.client.ui.Theme; -import envoy.client.ui.UserComponent; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentList.SelectionMode; import envoy.client.ui.list.Model; @@ -35,7 +34,7 @@ public class ContactsChooserDialog extends JDialog { private static final long serialVersionUID = -5774558118579032256L; - private ComponentList contactList = new ComponentList().setRenderer(UserComponent::new); + private ComponentList contactList = new ComponentList<>(); private JButton okButton = new JButton("Ok"); private JButton cancelButton = new JButton("Cancel"); @@ -77,7 +76,7 @@ public class ContactsChooserDialog extends JDialog { dialog.setVisible(true); dialog.repaint(); dialog.revalidate(); - return results; + return results.size() > 0 ? results : null; } /** @@ -85,12 +84,11 @@ public class ContactsChooserDialog extends JDialog { */ private ContactsChooserDialog() { contactList.setSelectionMode(SelectionMode.MULTIPLE); - contactList - .setSelectionHandler((user, comp, isSelected) -> comp.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor())); + // setBounds(100, 100, 450, 300); setModal(true); getContentPane().setLayout(new BorderLayout()); setBackground(theme.getBackgroundColor()); - setForeground(theme.getMessageTextColor()); + setForeground(theme.getTextColor()); contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); getContentPane().add(contentPanel, BorderLayout.CENTER); contentPanel.setLayout(new BorderLayout(0, 0)); diff --git a/src/main/java/envoy/client/ui/container/ContextMenu.java b/src/main/java/envoy/client/ui/container/ContextMenu.java new file mode 100755 index 0000000..facfe73 --- /dev/null +++ b/src/main/java/envoy/client/ui/container/ContextMenu.java @@ -0,0 +1,246 @@ +package envoy.client.ui.container; + +import java.awt.Color; +import java.awt.Component; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.*; + +import envoy.client.ui.Theme; + +/** + * This class defines a menu that will be automatically called if + * {@link MouseEvent#isPopupTrigger()} returns true for the parent component. + * The user has the possibility to directly add actions to be performed when + * clicking on the element with the selected String. Additionally, for each + * element an {@link Icon} can be added, but it must not be. + * If the key(text) of an element starts with one of the predefined values, a + * special component will be called: either a {@link JRadioButtonMenuItem}, a + * {@link JCheckBoxMenuItem} or a {@link JMenu} will be created.
+ *
+ * Project: envoy-client
+ * File: ContextMenu.java
+ * Created: 17 Mar 2020
+ * + * @author Leon Hofmeister + * @since Envoy v0.1-beta + */ +public class ContextMenu extends JPopupMenu { + + private static final long serialVersionUID = 2177146471226992104L; + + /** + * If a key starts with this String, a {@link JCheckBoxMenuItem} will be created + */ + public static final String checkboxMenuItem = "ChBoMI"; + /** + * If a key starts with this String, a {@link JRadioButtonMenuItem} will be + * created + */ + public static final String radioButtonMenuItem = "RaBuMI"; + /** + * If a key starts with this String, a {@link JMenu} will be created + */ + public static final String subMenuItem = "SubMI"; + + private Map items = new HashMap<>(); + private Map icons = new HashMap<>(); + private Map mnemonics = new HashMap<>(); + + private ButtonGroup radioButtonGroup = new ButtonGroup(); + private boolean built = false; + private boolean visible = false; + + /** + * @param parent the component which will call this + * {@link ContextMenu} + * @since Envoy v0.1-beta + */ + public ContextMenu(Component parent) { setInvoker(parent); } + + /** + * @param label the string that a UI may use to display as a title + * for the pop-up menu + * @param parent the component which will call this + * {@link ContextMenu} + * @param itemsWithActions a map of all strings to be displayed with according + * actions + * @param itemIcons the icons to be displayed before a name, if wanted. + * Only keys in here will have an Icon displayed. More + * precisely, all keys here not included in the first + * map will be thrown out. + * @param itemMnemonics the keyboard shortcuts that need to be pressed to + * automatically execute the {@link JMenuItem} with the + * given text + * @since Envoy v0.1-beta + */ + public ContextMenu(String label, Component parent, Map itemsWithActions, Map itemIcons, + Map itemMnemonics) { + super(label); + setInvoker(parent); + this.items = (itemsWithActions != null) ? itemsWithActions : items; + this.icons = (itemIcons != null) ? itemIcons : icons; + this.mnemonics = (itemMnemonics != null) ? itemMnemonics : mnemonics; + } + + /** + * Prepares the PopupMenu to be displayed. Should only be used once all map + * values have been set. + * + * @return this instance of {@link ContextMenu} to allow chaining behind the + * constructor + * @since Envoy v0.1-beta + */ + public ContextMenu build() { + items.forEach((text, action) -> { + // case radio button wanted + AbstractButton item; + if (text.startsWith(radioButtonMenuItem)) { + item = new JRadioButtonMenuItem(text.substring(radioButtonMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); + radioButtonGroup.add(item); + // case check box wanted + } else if (text.startsWith(checkboxMenuItem)) + item = new JCheckBoxMenuItem(text.substring(checkboxMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); + // case sub-menu wanted + else if (text.startsWith(subMenuItem)) item = new JMenu(text.substring(subMenuItem.length())); + else // normal JMenuItem wanted + item = new JMenuItem(text, icons.containsKey(text) ? icons.get(text) : null); + item.addActionListener(action); + if (mnemonics.containsKey(text)) item.setMnemonic(mnemonics.get(text)); + add(item); + }); + getInvoker().addMouseListener(getShowingListener()); + built = true; + return this; + } + + /** + * @param label the string that a UI may use to display as a title for the + * pop-up menu. + * @since Envoy v0.1-beta + */ + public ContextMenu(String label) { super(label); } + + private MouseAdapter getShowingListener() { + return new MouseAdapter() { + + @Override + public void mouseClicked(MouseEvent e) { action(e); } + + @Override + public void mousePressed(MouseEvent e) { action(e); } + + @Override + public void mouseReleased(MouseEvent e) { action(e); } + + private void action(MouseEvent e) { + if (!built) build(); + if (e.isPopupTrigger()) { + // hides the menu if already visible + visible = !visible; + if (visible) show(e.getComponent(), e.getX(), e.getY()); + else setVisible(false); + + } + } + }; + } + + /** + * Removes all subcomponents of this menu. + * + * @since Envoy v0.1-beta + */ + public void clear() { + removeAll(); + items = new HashMap<>(); + icons = new HashMap<>(); + mnemonics = new HashMap<>(); + } + + /** + * @return the items + * @since Envoy v0.1-beta + */ + public Map getItems() { return items; } + + /** + * @param items the items with the displayed text and the according action to + * take once called + * @since Envoy v0.1-beta + */ + public void setItems(Map items) { this.items = items; } + + /** + * @return the icons + * @since Envoy v0.1-beta + */ + public Map getIcons() { return icons; } + + /** + * @param icons the icons to set + * @since Envoy v0.1-beta + */ + public void setIcons(Map icons) { this.icons = icons; } + + /** + * @return the mnemonics (the keyboard shortcuts that automatically execute the + * command for a {@link JMenuItem} with corresponding text) + * @since Envoy v0.1-beta + */ + public Map getMnemonics() { return mnemonics; } + + /** + * @param mnemonics the keyboard shortcuts that need to be pressed to + * automatically execute the {@link JMenuItem} with the given + * text + * @since Envoy v0.1-beta + */ + public void setMnemonics(Map mnemonics) { this.mnemonics = mnemonics; } + + /** + * {@inheritDoc}
+ * Additionally sets the foreground of all subcomponents of this + * {@link ContextMenu}. + * + * @since Envoy v0.1-beta + */ + @Override + public void setForeground(Color color) { + super.setForeground(color); + for (MenuElement element : getSubElements()) + ((Component) element).setForeground(color); + } + + /** + * {@inheritDoc}
+ * Additionally sets the background of all subcomponents of this + * {@link ContextMenu}. + * + * @since Envoy v0.1-beta + */ + @Override + public void setBackground(Color color) { + super.setBackground(color); + for (MenuElement element : getSubElements()) + ((Component) element).setBackground(color); + } + + /** + * Sets the fore- and background of all elements contained in this + * {@link ContextMenu} + * This method is to be only used by Envoy as {@link Theme} is an + * Envoy-exclusive object. + * + * @param theme the theme to use + * @since Envoy v0.1-beta + */ + protected void applyTheme(Theme theme) { + setBackground(theme.getInteractableBackgroundColor()); + setForeground(theme.getTextColor()); + } +} diff --git a/src/main/java/envoy/client/ui/list/SelectionHandler.java b/src/main/java/envoy/client/ui/list/SelectionHandler.java index b6ed40a..998bee2 100644 --- a/src/main/java/envoy/client/ui/list/SelectionHandler.java +++ b/src/main/java/envoy/client/ui/list/SelectionHandler.java @@ -10,6 +10,7 @@ import javax.swing.JComponent; * Created: 21.03.2020 * * @author Kai S. K. Engelbart + * @param the type of the underlying {@link ComponentList} * @since Envoy v0.1-beta */ @FunctionalInterface @@ -17,9 +18,9 @@ public interface SelectionHandler { /** * Notifies the handler about a selection. - * - * @param element the selected element - * @param component the selected component + * + * @param element the selected element + * @param component the selected component * @param isSelected contains the selection state * @since Envoy v0.1-beta */ diff --git a/src/main/java/envoy/client/ui/ContactSearchComponent.java b/src/main/java/envoy/client/ui/list_component/ContactSearchComponent.java similarity index 89% rename from src/main/java/envoy/client/ui/ContactSearchComponent.java rename to src/main/java/envoy/client/ui/list_component/ContactSearchComponent.java index 39ae50b..16acaa4 100644 --- a/src/main/java/envoy/client/ui/ContactSearchComponent.java +++ b/src/main/java/envoy/client/ui/list_component/ContactSearchComponent.java @@ -1,4 +1,4 @@ -package envoy.client.ui; +package envoy.client.ui.list_component; import java.awt.Component; import java.awt.Dimension; @@ -26,6 +26,11 @@ public class ContactSearchComponent extends JComponent { private static final long serialVersionUID = 3166795412575239455L; + /** + * @param list the {@link ComponentList} that is used to display search results + * @param user the {@link User} that appears as a search result + * @since Envoy v0.1-beta + */ public ContactSearchComponent(ComponentList list, User user) { setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); @@ -33,7 +38,7 @@ public class ContactSearchComponent extends JComponent { setForeground(list.getForeground()); JLabel display = new JLabel(user.getName()); - display.setForeground(Settings.getInstance().getCurrentTheme().getMessageTextColor()); + display.setForeground(Settings.getInstance().getCurrentTheme().getTextColor()); display.setAlignmentX(Component.LEFT_ALIGNMENT); display.setAlignmentY(Component.CENTER_ALIGNMENT); display.setFont(new Font("Arial", Font.PLAIN, 16)); diff --git a/src/main/java/envoy/client/ui/MessageComponent.java b/src/main/java/envoy/client/ui/list_component/MessageComponent.java similarity index 84% rename from src/main/java/envoy/client/ui/MessageComponent.java rename to src/main/java/envoy/client/ui/list_component/MessageComponent.java index a4a83a0..4b6ca83 100644 --- a/src/main/java/envoy/client/ui/MessageComponent.java +++ b/src/main/java/envoy/client/ui/list_component/MessageComponent.java @@ -1,4 +1,4 @@ -package envoy.client.ui; +package envoy.client.ui.list_component; import java.awt.*; import java.io.IOException; @@ -7,10 +7,14 @@ import java.util.EnumMap; import javax.swing.*; +import envoy.client.data.Chat; import envoy.client.data.Settings; +import envoy.client.ui.Color; +import envoy.client.ui.IconUtil; import envoy.client.ui.list.ComponentList; import envoy.data.Message; import envoy.data.Message.MessageStatus; +import envoy.data.User; /** * Project: envoy-client @@ -36,11 +40,15 @@ public class MessageComponent extends JPanel { } } + /** + * @param list the {@link ComponentList} that displays this {@link Chat} + * @param message the {@link Message} to display + * @param senderId the id of the {@link User} who sends messages from this + * account + * @since Envoy v0.1-beta + */ public MessageComponent(ComponentList list, Message message, long senderId) { - this(list.getMaximumSize().width, message, senderId); - } - - public MessageComponent(int width, Message message, long senderId) { + var width = list.getMaximumSize().width; final var theme = Settings.getInstance().getCurrentTheme(); final int padding = (int) (width * 0.35); @@ -70,7 +78,7 @@ public class MessageComponent extends JPanel { var messageTextArea = new JTextArea(message.getText()); messageTextArea.setLineWrap(true); messageTextArea.setWrapStyleWord(true); - messageTextArea.setForeground(theme.getMessageTextColor()); + messageTextArea.setForeground(theme.getTextColor()); messageTextArea.setAlignmentX(0.5f); messageTextArea.setBackground(theme.getCellColor()); messageTextArea.setEditable(false); @@ -107,8 +115,7 @@ public class MessageComponent extends JPanel { // Define an etched border and some space to the messages below var ours = senderId == message.getSenderId(); - setBorder(BorderFactory.createCompoundBorder( - BorderFactory.createEmptyBorder(0, ours ? padding : 10, 10, ours ? 0 : padding), + setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, ours ? padding : 10, 10, ours ? 0 : padding), BorderFactory.createEtchedBorder())); var size = new Dimension(width - 50, getPreferredSize().height); diff --git a/src/main/java/envoy/client/ui/UserComponent.java b/src/main/java/envoy/client/ui/list_component/UserComponent.java similarity index 83% rename from src/main/java/envoy/client/ui/UserComponent.java rename to src/main/java/envoy/client/ui/list_component/UserComponent.java index 7fd4392..4a9fbc7 100644 --- a/src/main/java/envoy/client/ui/UserComponent.java +++ b/src/main/java/envoy/client/ui/list_component/UserComponent.java @@ -1,4 +1,4 @@ -package envoy.client.ui; +package envoy.client.ui.list_component; import java.awt.BorderLayout; import java.awt.Dimension; @@ -7,11 +7,14 @@ import javax.swing.JComponent; import javax.swing.JLabel; import envoy.client.data.Settings; -import envoy.client.ui.list.ComponentList; +import envoy.client.ui.Color; +import envoy.client.ui.Theme; import envoy.data.User; import envoy.data.User.UserStatus; /** + * Displays a {@link User}.
+ *
* Project: envoy-client * File: UserComponent.java * Created: 21.03.2020 @@ -23,7 +26,11 @@ public class UserComponent extends JComponent { private static final long serialVersionUID = 8450602172939729585L; - public UserComponent(ComponentList list, User user) { + /** + * @param user the {@link User} whose information is displayed + * @since Envoy v0.1-beta + */ + public UserComponent(User user) { final Theme theme = Settings.getInstance().getCurrentTheme(); setLayout(new BorderLayout()); diff --git a/src/main/java/envoy/client/ui/list_component/package-info.java b/src/main/java/envoy/client/ui/list_component/package-info.java new file mode 100644 index 0000000..053d2bd --- /dev/null +++ b/src/main/java/envoy/client/ui/list_component/package-info.java @@ -0,0 +1,14 @@ +/** + * This package contains swing components that can be displayed by + * {@link envoy.client.ui.list.ComponentList}.
+ *
+ * Project: envoy-client
+ * File: package-info.java
+ * Created: 21 Mar 2020
+ * + * @author Leon Hofmeister + * @author Kai S. K. Engelbart + * @author Maximilian Käfer + * @since Envoy v0.1-beta + */ +package envoy.client.ui.list_component; diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java old mode 100644 new mode 100755 index 5408a05..997dae5 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -38,9 +38,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { private final Insets insets = new Insets(5, 5, 5, 5); - private static final Settings settings = Settings.getInstance(); - private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class); - private static final long serialVersionUID = -8697897390666456624L; + private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class); + private static final long serialVersionUID = -8697897390666456624L; /** * Initializes a {@link ThemeCustomizationPanel} that enables the user to change @@ -53,7 +52,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { */ public ThemeCustomizationPanel(SettingsScreen parent) { super(parent); - temporaryTheme = new Theme("temporaryTheme", settings.getCurrentTheme()); + temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getCurrentTheme()); GridBagLayout gbl_themeLayout = new GridBagLayout(); @@ -64,7 +63,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { setLayout(gbl_themeLayout); - themes.setSelectedItem(settings.getCurrentTheme()); + themes.setSelectedItem(Settings.getInstance().getCurrentTheme()); GridBagConstraints gbc_themes = new GridBagConstraints(); gbc_themes.fill = GridBagConstraints.HORIZONTAL; @@ -84,7 +83,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.setLayout(gbl_colorCustomizations); - Theme theme = settings.getCurrentTheme(); + Theme theme = Settings.getInstance().getCurrentTheme(); buildCustomizeElements(theme); GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); @@ -174,7 +173,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor", 2); buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3); buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor", 4); - buildCustomizeElement(theme, theme.getMessageTextColor(), "Messages Chat", "messageColorChat", 5); + buildCustomizeElement(theme, theme.getTextColor(), "Text Color", "textColor", 5); buildCustomizeElement(theme, theme.getDateColor(), "Date Chat", "dateColorChat", 6); buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor", 7); buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor", 8); From 1f1d15d0fa880900fda813754918bd1ee4553f60 Mon Sep 17 00:00:00 2001 From: Haramus Samsamus Date: Sun, 22 Mar 2020 10:30:04 +0100 Subject: [PATCH 283/474] Update README.md --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c451b13..36901ac 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,8 @@
**Envoy Client** is one of two repositories needed to use the messenger Envoy.
-The other one is **Envoy Common**.
-In the future, Envoy Common might be discarded, but for now, both Repositories are required in order to use Envoy to send messages to other people.
-




+The other one is **Envoy Common**. +








## Features @@ -20,7 +19,6 @@ Currently existing features are: * Appealing user interface * Changeable themes that store the colors used in _Envoy_ * Possibility to run _Envoy_ in the Background once it has been started - * **Attention**: currently works solely on Windows and Mac * Possibility to exit _Envoy_ * Connectivity * Sending messages to another person via a predefined server @@ -28,7 +26,7 @@ Currently existing features are: * Programming * API to change default configuration * Advanced logging possibilities - * Access without Admin rights possible via local message storage in the home folder + * Access without Admin rights possible via local message storage in the home folder * Tons of Events to interact with * Detailed Javadoc to improve readability of code From 68c73441372e3df9fabe6534f6f905c626b91ab8 Mon Sep 17 00:00:00 2001 From: delvh Date: Sun, 22 Mar 2020 16:51:44 +0100 Subject: [PATCH 284/474] ContactsChooserDialog is now centered around a parent component additionally: * fixed bug not updating date color when changing themes * improved style of forwardMessage-Methoden --- .../envoy/client/ui/container/ChatWindow.java | 23 ++++++++----------- .../ui/container/ContactsChooserDialog.java | 21 +++++++++++------ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index 6f16af4..b762ceb 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -154,6 +154,7 @@ public class ChatWindow extends JFrame { }); scrollPane.setViewportView(messageList); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.addComponentListener(new ComponentAdapter() { // Update list elements when scroll pane (and thus list) is resized @@ -163,7 +164,6 @@ public class ChatWindow extends JFrame { messageList.synchronizeModel(); } }); - scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); GridBagConstraints gbc_scrollPane = new GridBagConstraints(); gbc_scrollPane.fill = GridBagConstraints.BOTH; @@ -213,7 +213,6 @@ public class ChatWindow extends JFrame { gbc_postButton.fill = GridBagConstraints.BOTH; gbc_postButton.gridx = 2; gbc_postButton.gridy = 3; - gbc_postButton.insets = insets; postButton.addActionListener((evt) -> { postMessage(); }); @@ -494,6 +493,7 @@ public class ChatWindow extends JFrame { // messageList messageList.setForeground(theme.getTextColor()); messageList.setBackground(theme.getCellColor()); + messageList.synchronizeModel(); // scrollPane scrollPane.applyTheme(theme); scrollPane.autoscroll(); @@ -544,9 +544,6 @@ public class ChatWindow extends JFrame { } String text = messageEnterTextArea.getText().trim(); if (!text.isEmpty()) checkMessageTextLength(); - // delete final line break, if present (especially if "Enter" is used to send - // the message) - if (text.endsWith(System.getProperty("line.separator"))) text = text.substring(0, text.lastIndexOf(System.getProperty("line.separator"))); // Create message final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator()) @@ -560,21 +557,21 @@ public class ChatWindow extends JFrame { /** * Forwards a message. * - * @param msg the message to forward + * @param message the message to forward * @param recipient the new recipient of the message * @since Envoy v0.1-beta */ - private void forwardMessage(Message msg, User recipient) { - sendMessage(new MessageBuilder(msg, recipient.getId(), localDb.getIdGenerator()).build()); - } + private void forwardMessage(Message message, User... recipients) { + Arrays.stream(recipients).forEach(recipient -> { + if (message != null && recipients != null) sendMessage(new MessageBuilder(message, recipient.getId(), localDb.getIdGenerator()).build()); + else throw new NullPointerException("No recipient or no message selected"); + }); - private void forwardMessageToMultipleUsers(Message message, Collection recipients) { - recipients.forEach(recipient -> forwardMessage(message, recipient)); } @SuppressWarnings("unused") - private void forwardMultipleMessagesToMultipleUsers(Collection messages, Collection recipients) { - messages.forEach(message -> forwardMessageToMultipleUsers(message, recipients)); + private void forwardMessages(Collection messages, User... recipients) { + messages.forEach(message -> { forwardMessage(message, recipients); }); } /** diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java index 5677e7d..b507cbc 100755 --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -1,9 +1,11 @@ package envoy.client.ui.container; import java.awt.BorderLayout; +import java.awt.Component; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import javax.swing.JButton; @@ -12,7 +14,6 @@ import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import envoy.client.data.Settings; -import envoy.client.net.Client; import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentList.SelectionMode; @@ -34,7 +35,7 @@ public class ContactsChooserDialog extends JDialog { private static final long serialVersionUID = -5774558118579032256L; - private ComponentList contactList = new ComponentList<>(); + private ComponentList contactList = new ComponentList().setModel(new Model()); private JButton okButton = new JButton("Ok"); private JButton cancelButton = new JButton("Cancel"); @@ -54,14 +55,17 @@ public class ContactsChooserDialog extends JDialog { * ArrayList. * * @param title the title of the dialog + * @param parent this @{@link Component} will be parsed to + * {@link java.awt.Window#setLocationRelativeTo(Component)} in + * order to change the location of the dialog * @param message the {@link Message} to display on top of the Dialog - * @param client the client whose contacts should be displayed + * @param users the users that should be displayed * @return the selected Element (yet has to be casted to the wanted type due to * the Generics limitations in Java) * @since Envoy v0.1-beta */ - public static List showForwardingDialog(String title, Message message, Client client) { - ContactsChooserDialog dialog = new ContactsChooserDialog(); + public static List showForwardingDialog(String title, Component parent, Message message, Collection users) { + ContactsChooserDialog dialog = new ContactsChooserDialog(parent); dialog.setTitle(title); dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE); dialog.addCancelButtonActionListener(e -> dialog.dispose()); @@ -72,7 +76,7 @@ public class ContactsChooserDialog extends JDialog { List results = new ArrayList<>(); dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelectedElements()); dialog.dispose(); }); Model contactListModel = dialog.getContactList().getModel(); - client.getContacts().getContacts().forEach(user -> contactListModel.add(user)); + users.forEach(contactListModel::add); dialog.setVisible(true); dialog.repaint(); dialog.revalidate(); @@ -80,12 +84,15 @@ public class ContactsChooserDialog extends JDialog { } /** + * @param parent this @{@link Component} will be parsed to + * {@link java.awt.Window#setLocationRelativeTo(Component)} * @since Envoy v0.1-beta */ - private ContactsChooserDialog() { + private ContactsChooserDialog(Component parent) { contactList.setSelectionMode(SelectionMode.MULTIPLE); // setBounds(100, 100, 450, 300); setModal(true); + setLocationRelativeTo(parent); getContentPane().setLayout(new BorderLayout()); setBackground(theme.getBackgroundColor()); setForeground(theme.getTextColor()); From 156beaf44b24ee567d7078f3e9d88eeae2575d60 Mon Sep 17 00:00:00 2001 From: delvh Date: Sun, 22 Mar 2020 17:05:28 +0100 Subject: [PATCH 285/474] Fixes #121 (first displayed theme is current theme) Additionally removed okButton from SettingsScreen --- .../envoy/client/ui/list/ComponentList.java | 6 +- .../ui/settings/GeneralSettingsPanel.java | 182 +++++++++--------- .../client/ui/settings/SettingsPanel.java | 11 +- .../client/ui/settings/SettingsScreen.java | 20 -- .../ui/settings/ThemeCustomizationPanel.java | 87 +++++---- 5 files changed, 146 insertions(+), 160 deletions(-) diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 44d98de..68b92a2 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -110,7 +110,7 @@ public class ComponentList extends JPanel { /** * Removes the current selection. - * + * * @since Envoy v0.1-alpha */ public void clearSelection() { @@ -173,7 +173,7 @@ public class ComponentList extends JPanel { * @throws java.util.NoSuchElementException if no selection is present * @since Envoy v0.1-beta */ - public int getSingleSelection() { return selection.iterator().next(); } + public int getSingleSelection() { return selection.stream().findAny().get(); } /** * @return an arbitrary selected element @@ -235,7 +235,7 @@ public class ComponentList extends JPanel { /** * Sets a new selection mode. The current selection will be cleared during this * action. - * + * * @param selectionMode the selection mode to set * @return this component list * @since Envoy v0.1-beta diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index fbc3952..ce40e91 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -1,93 +1,89 @@ -package envoy.client.ui.settings; - -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.event.ActionListener; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.swing.JComponent; -import javax.swing.JTextPane; - -import envoy.client.data.Settings; -import envoy.client.data.SettingsItem; -import envoy.client.ui.Theme; -import envoy.util.EnvoyLog; - -/** - * Displays GUI components that allow general settings regarding the client.
- *
- * Project: envoy-client
- * File: GeneralSettingsPanel.java
- * Created: 21 Dec 2019
- * - * @author Maximilian Käfer - * @since Envoy v0.3-alpha - */ -public class GeneralSettingsPanel extends SettingsPanel { - - private Theme theme; - - private static final String[] items = { "onCloseMode", "enterToSend" }; - private static final Logger logger = EnvoyLog.getLogger(GeneralSettingsPanel.class); - private static final long serialVersionUID = -7470848775130754239L; - - /** - * This is the constructor for the General class. Here the user can set general - * settings for the client. - * - * @param parent the {@link SettingsScreen} as a part of which this - * {@link SettingsPanel} is displayed - * @since Envoy v0.3-alpha - */ - public GeneralSettingsPanel(SettingsScreen parent) { - super(parent); - theme = Settings.getInstance().getCurrentTheme(); - - setBackground(theme.getCellColor()); - - GridBagLayout gbl_general = new GridBagLayout(); - gbl_general.columnWidths = new int[] { 1, 1 }; - gbl_general.rowHeights = new int[] { 1, 1, 1 }; - gbl_general.columnWeights = new double[] { 1.0, 0.1 }; - gbl_general.rowWeights = new double[] { 0.02, 0.02, 1.0 }; - - setLayout(gbl_general); - - for (int i = 0; i < items.length; i++) - try { - createSettingElement(i, Settings.getInstance().getItems().get(items[i])); - } catch (SecurityException | ReflectiveOperationException e) { - logger.log(Level.WARNING, "Could not create settings item", e); - } - } - - private void createSettingElement(int gridy, SettingsItem settingsItem) throws SecurityException, ReflectiveOperationException { - JTextPane descriptionText = new JTextPane(); - - JComponent settingComponent = settingsItem.getComponent(); - - GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); - gbc_toggleSwitch.gridx = 1; - gbc_toggleSwitch.gridy = gridy; - - add(settingComponent, gbc_toggleSwitch); - - descriptionText.setText(settingsItem.getDescription()); - descriptionText.setBackground(theme.getBackgroundColor()); - descriptionText.setForeground(theme.getBackgroundColor().invert()); - descriptionText.setEditable(false); - - GridBagConstraints gbc_descriptionText = new GridBagConstraints(); - gbc_descriptionText.fill = GridBagConstraints.BOTH; - gbc_descriptionText.gridx = 0; - gbc_descriptionText.gridy = gridy; - gbc_descriptionText.insets = new Insets(5, 5, 5, 5); - - add(descriptionText, gbc_descriptionText); - } - - @Override - public ActionListener getOkButtonAction() { return evt -> {}; } -} +package envoy.client.ui.settings; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.JComponent; +import javax.swing.JTextPane; + +import envoy.client.data.Settings; +import envoy.client.data.SettingsItem; +import envoy.client.ui.Theme; +import envoy.util.EnvoyLog; + +/** + * Displays GUI components that allow general settings regarding the client.
+ *
+ * Project: envoy-client
+ * File: GeneralSettingsPanel.java
+ * Created: 21 Dec 2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.3-alpha + */ +public class GeneralSettingsPanel extends SettingsPanel { + + private Theme theme; + + private static final String[] items = { "onCloseMode", "enterToSend" }; + private static final Logger logger = EnvoyLog.getLogger(GeneralSettingsPanel.class); + private static final long serialVersionUID = -7470848775130754239L; + + /** + * This is the constructor for the General class. Here the user can set general + * settings for the client. + * + * @param parent the {@link SettingsScreen} as a part of which this + * {@link SettingsPanel} is displayed + * @since Envoy v0.3-alpha + */ + public GeneralSettingsPanel(SettingsScreen parent) { + super(parent); + theme = Settings.getInstance().getCurrentTheme(); + + setBackground(theme.getCellColor()); + + GridBagLayout gbl_general = new GridBagLayout(); + gbl_general.columnWidths = new int[] { 1, 1 }; + gbl_general.rowHeights = new int[] { 1, 1, 1 }; + gbl_general.columnWeights = new double[] { 1.0, 0.1 }; + gbl_general.rowWeights = new double[] { 0.02, 0.02, 1.0 }; + + setLayout(gbl_general); + + for (int i = 0; i < items.length; i++) + try { + createSettingElement(i, Settings.getInstance().getItems().get(items[i])); + } catch (SecurityException | ReflectiveOperationException e) { + logger.log(Level.WARNING, "Could not create settings item", e); + } + } + + private void createSettingElement(int gridy, SettingsItem settingsItem) throws SecurityException, ReflectiveOperationException { + JTextPane descriptionText = new JTextPane(); + + JComponent settingComponent = settingsItem.getComponent(); + + GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); + gbc_toggleSwitch.gridx = 1; + gbc_toggleSwitch.gridy = gridy; + + add(settingComponent, gbc_toggleSwitch); + + descriptionText.setText(settingsItem.getDescription()); + descriptionText.setBackground(theme.getBackgroundColor()); + descriptionText.setForeground(theme.getBackgroundColor().invert()); + descriptionText.setEditable(false); + + GridBagConstraints gbc_descriptionText = new GridBagConstraints(); + gbc_descriptionText.fill = GridBagConstraints.BOTH; + gbc_descriptionText.gridx = 0; + gbc_descriptionText.gridy = gridy; + gbc_descriptionText.insets = new Insets(5, 5, 5, 5); + + add(descriptionText, gbc_descriptionText); + } +} diff --git a/src/main/java/envoy/client/ui/settings/SettingsPanel.java b/src/main/java/envoy/client/ui/settings/SettingsPanel.java index 80469c5..421b774 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/SettingsPanel.java @@ -1,7 +1,5 @@ package envoy.client.ui.settings; -import java.awt.event.ActionListener; - import javax.swing.JPanel; /** @@ -24,16 +22,9 @@ public abstract class SettingsPanel extends JPanel { /** * Initializes a {@link SettingsPanel}. - * + * * @param parent the {@link SettingsScreen} as a part of which this * {@link SettingsPanel} is displayed */ public SettingsPanel(SettingsScreen parent) { this.parent = parent; } - - /** - * @return an {@link ActionListener} that should be invoked when the OK button - * is pressed in the {@link SettingsScreen} - * @since Envoy v0.2-alpha - */ - public abstract ActionListener getOkButtonAction(); } diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 22a24a4..0c98084 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -40,7 +40,6 @@ public class SettingsScreen extends JDialog { // OK and cancel buttons private final JPanel buttonPane = new JPanel(); - private final PrimaryButton okButton = new PrimaryButton("Save"); private final PrimaryButton cancelButton = new PrimaryButton("Cancel"); private final Insets insets = new Insets(5, 5, 5, 5); @@ -138,21 +137,6 @@ public class SettingsScreen extends JDialog { cancelButton.addActionListener((evt) -> { dispose(); }); } - { - okButton.setActionCommand("OK"); - okButton.setBorderPainted(false); - GridBagConstraints gbc_okButton = new GridBagConstraints(); - gbc_okButton.anchor = GridBagConstraints.NORTHEAST; - gbc_okButton.fill = GridBagConstraints.EAST; - gbc_okButton.insets = insets; - gbc_okButton.gridx = 2; - gbc_okButton.gridy = 0; - buttonPane.add(okButton, gbc_okButton); - getRootPane().setDefaultButton(okButton); - - // Invoke settings panel action on button press - okButton.addActionListener((evt) -> { if (settingsPanel != null) settingsPanel.getOkButtonAction().actionPerformed(evt); }); - } } // Apply current theme @@ -179,10 +163,6 @@ public class SettingsScreen extends JDialog { cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor()); - // okButton - okButton.setBackground(theme.getInteractableBackgroundColor()); - okButton.setForeground(theme.getInteractableForegroundColor()); - // options options.setSelectionForeground(theme.getUserNameColor()); options.setSelectionBackground(theme.getSelectionColor()); diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 997dae5..a68a6a5 100755 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -1,7 +1,6 @@ package envoy.client.ui.settings; import java.awt.*; -import java.awt.event.ActionListener; import java.util.logging.Level; import java.util.logging.Logger; @@ -11,6 +10,7 @@ import envoy.client.data.Settings; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.Color; import envoy.client.ui.Theme; +import envoy.client.ui.primary.PrimaryButton; import envoy.event.EventBus; import envoy.util.EnvoyLog; @@ -30,13 +30,13 @@ public class ThemeCustomizationPanel extends SettingsPanel { private JPanel colorsPanel = new JPanel(); - private DefaultComboBoxModel themesModel = new DefaultComboBoxModel<>( - Settings.getInstance().getThemes().keySet().toArray(new String[0])); - private JComboBox themes = new JComboBox<>(themesModel); + private DefaultComboBoxModel themesModel; + private JComboBox themes; private Theme temporaryTheme; - private boolean themeChanged; + private PrimaryButton createThemeButton = new PrimaryButton("Create Theme"); - private final Insets insets = new Insets(5, 5, 5, 5); + private boolean themeChanged; + private final Insets insets = new Insets(5, 5, 5, 5); private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class); private static final long serialVersionUID = -8697897390666456624L; @@ -54,12 +54,22 @@ public class ThemeCustomizationPanel extends SettingsPanel { super(parent); temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getCurrentTheme()); + var themeNames = Settings.getInstance().getThemes().keySet().toArray(new String[0]); + String currentThemeName = Settings.getInstance().getCurrentThemeName(); + for (int i = 0; i < themeNames.length; i++) + if (currentThemeName.equals(themeNames[i])) { + themeNames[i] = themeNames[0]; + themeNames[0] = currentThemeName; + break; + } + themesModel = new DefaultComboBoxModel<>(themeNames); + themes = new JComboBox<>(themesModel); GridBagLayout gbl_themeLayout = new GridBagLayout(); gbl_themeLayout.columnWidths = new int[] { 1, 1 }; - gbl_themeLayout.rowHeights = new int[] { 1, 1 }; + gbl_themeLayout.rowHeights = new int[] { 1, 1, 1 }; gbl_themeLayout.columnWeights = new double[] { 1.0, 1.0 }; - gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0 }; + gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0, 0.01 }; setLayout(gbl_themeLayout); @@ -95,6 +105,37 @@ public class ThemeCustomizationPanel extends SettingsPanel { gbc_colorsPanel.insets = insets; add(colorsPanel, gbc_colorsPanel); + + createThemeButton.addActionListener((evt) -> { + if (themeChanged) { + new NewThemeScreen(parent, name -> { + // Create new theme + logger.log(Level.FINEST, name); + Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); + + // Add new theme name to combo box + themesModel.addElement(name); + + // Select new theme name + themes.setSelectedIndex(themesModel.getSize() - 1); + }, name -> { + // Modify theme + Settings.getInstance().getThemes().replace(name, new Theme(name, temporaryTheme)); + if (themes.getSelectedItem().equals(name)) + EventBus.getInstance().dispatch(new ThemeChangeEvent(Settings.getInstance().getTheme(name))); + else themes.setSelectedItem(name); + }).setVisible(true); + themeChanged = false; + } + }); + GridBagConstraints gbc_createThemeButton = new GridBagConstraints(); + gbc_createThemeButton.fill = GridBagConstraints.HORIZONTAL; + gbc_createThemeButton.gridx = 0; + gbc_createThemeButton.gridy = 2; + gbc_createThemeButton.anchor = GridBagConstraints.CENTER; + gbc_createThemeButton.insets = insets; + add(createThemeButton, gbc_createThemeButton); + colorsPanel.setBackground(theme.getCellColor()); // Apply theme upon selection @@ -120,37 +161,15 @@ public class ThemeCustomizationPanel extends SettingsPanel { }); } - @Override - public ActionListener getOkButtonAction() { - return (evt) -> { - if (themeChanged) { - new NewThemeScreen(parent, name -> { - // Create new theme - logger.log(Level.FINEST, name); - Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); - - // Add new theme name to combo box - themesModel.addElement(name); - - // Select new theme name - themes.setSelectedIndex(themesModel.getSize() - 1); - }, name -> { - // Modify theme - Settings.getInstance().getThemes().replace(name, new Theme(name, temporaryTheme)); - if (themes.getSelectedItem().equals(name)) - EventBus.getInstance().dispatch(new ThemeChangeEvent(Settings.getInstance().getTheme(name))); - else themes.setSelectedItem(name); - }).setVisible(true); - themeChanged = false; - } - }; - } - private void applyTheme(Theme theme) { // themeContent setForeground(theme.getUserNameColor()); setBackground(theme.getCellColor()); + // createThemeButton + createThemeButton.setForeground(theme.getInteractableForegroundColor()); + createThemeButton.setBackground(theme.getInteractableBackgroundColor()); + // themes themes.setBackground(theme.getInteractableBackgroundColor()); themes.setForeground(theme.getInteractableForegroundColor()); From ceb50cd01cedc58fa72060155200e70c975e6fca Mon Sep 17 00:00:00 2001 From: delvh Date: Sun, 22 Mar 2020 17:20:05 +0100 Subject: [PATCH 286/474] Added disabling of postButton while String.isBlank() returns true --- .../envoy/client/ui/container/ChatWindow.java | 90 ++++++++++--------- 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index b762ceb..a2c2f9a 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -4,9 +4,7 @@ import java.awt.*; import java.awt.datatransfer.StringSelection; import java.awt.event.*; import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; @@ -118,39 +116,44 @@ public class ChatWindow extends JFrame { gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; gbl_contentPane.rowHeights = new int[] { 1, 1, 1, 1 }; gbl_contentPane.columnWeights = new double[] { 0.03, 1.0, 0.1 }; - gbl_contentPane.rowWeights = new double[] { 0.03, 0.001, 1.0, 0.005 }; + gbl_contentPane.rowWeights = new double[] { 0.03, 0.001, 1.0, 0.001 }; contentPane.setLayout(gbl_contentPane); - // ContextMenu - Map commands = new HashMap<>() { - - private static final long serialVersionUID = -2755235774946990126L; - - { - put("forward selected message", - evt -> forwardMessageToMultipleUsers(messageList.getSingleSelectedElement(), - ContactsChooserDialog - .showForwardingDialog("Forward selected message to", messageList.getSingleSelectedElement(), client))); - put("copy", evt -> { - // TODO should be enhanced to allow also copying of message attachments, - // especially pictures - StringSelection copy = new StringSelection(messageList.getSingleSelectedElement().getText()); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); - }); - // TODO insert implementation to edit and delete messages - put("delete", evt -> {}); - put("edit", evt -> {}); - put("quote", evt -> {}); - } - }; - contextMenu = new ContextMenu(null, messageList, commands, null, null).build(); - messageList.setBorder(new EmptyBorder(space, space, space, space)); messageList.setSelectionMode(SelectionMode.SINGLE); messageList.setSelectionHandler((message, comp, isSelected) -> { final var theme = Settings.getInstance().getCurrentTheme(); comp.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); - contextMenu.show(comp, 0, 0); + + // ContextMenu + Map commands = new HashMap<>() { + + private static final long serialVersionUID = -2755235774946990126L; + + { + put("forward selected message", evt -> { + final Message selectedMessage = messageList.getSingleSelectedElement(); + forwardMessage(selectedMessage, + ContactsChooserDialog + .showForwardingDialog("Forward selected message to", null, selectedMessage, localDb.getUsers().values()) + .toArray(new User[0])); + }); + put("copy", evt -> { + // TODO should be enhanced to allow also copying of message attachments, + // especially pictures + StringSelection copy = new StringSelection(messageList.getSingleSelectedElement().getText()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); + }); + // TODO insert implementation to edit and delete messages + put("delete", evt -> {}); + put("edit", evt -> {}); + put("quote", evt -> {}); + } + }; + if (isSelected) { + contextMenu = new ContextMenu(null, comp, commands, null, null).build(); + contextMenu.show(comp, 0, 0); + } }); scrollPane.setViewportView(messageList); @@ -180,7 +183,10 @@ public class ChatWindow extends JFrame { messageEnterTextArea.addInputMethodListener(new InputMethodListener() { @Override - public void inputMethodTextChanged(InputMethodEvent event) { checkMessageTextLength(); } + public void inputMethodTextChanged(InputMethodEvent event) { + checkMessageTextLength(); + checkPostButton(messageEnterTextArea.getText()); + } @Override public void caretPositionChanged(InputMethodEvent event) {} @@ -191,31 +197,30 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER - && (Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0 || e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK)) + && (Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0 || e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK) + && postButton.isEnabled()) postMessage(); // Checking if text is too long checkMessageTextLength(); + checkPostButton(messageEnterTextArea.getText()); } }); - GridBagConstraints gbc_scrollPaneForTextInput = new GridBagConstraints(); - gbc_scrollPaneForTextInput.fill = GridBagConstraints.BOTH; - gbc_scrollPaneForTextInput.gridx = 1; - gbc_scrollPaneForTextInput.gridy = 3; - - gbc_scrollPaneForTextInput.insets = insets; - - contentPane.add(messageEnterTextArea, gbc_scrollPaneForTextInput); + GridBagConstraints gbc_messageEnterTextArea = new GridBagConstraints(); + gbc_messageEnterTextArea.fill = GridBagConstraints.BOTH; + gbc_messageEnterTextArea.gridx = 1; + gbc_messageEnterTextArea.gridy = 3; + gbc_messageEnterTextArea.insets = insets; + contentPane.add(messageEnterTextArea, gbc_messageEnterTextArea); // Post Button GridBagConstraints gbc_postButton = new GridBagConstraints(); - gbc_postButton.fill = GridBagConstraints.BOTH; gbc_postButton.gridx = 2; gbc_postButton.gridy = 3; gbc_postButton.insets = insets; - postButton.addActionListener((evt) -> { postMessage(); }); + postButton.setEnabled(false); contentPane.add(postButton, gbc_postButton); // Settings Button @@ -552,6 +557,7 @@ public class ChatWindow extends JFrame { sendMessage(message); // Clear text field messageEnterTextArea.setText(""); + postButton.setEnabled(false); } /** @@ -684,4 +690,6 @@ public class ChatWindow extends JFrame { JOptionPane.WARNING_MESSAGE); } } + + private void checkPostButton(String text) { postButton.setEnabled(!text.trim().isBlank()); } } From 930da62b79ea55ac6db1718ded24134373f409a5 Mon Sep 17 00:00:00 2001 From: delvh Date: Mon, 23 Mar 2020 21:04:32 +0100 Subject: [PATCH 287/474] Added renderer to ContactsChooserDialog --- .../envoy/client/ui/container/ChatWindow.java | 44 ++++++++----------- .../ui/container/ContactsChooserDialog.java | 22 +++++++++- .../envoy/client/ui/list/ComponentList.java | 5 ++- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index a2c2f9a..4d92a03 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -4,7 +4,10 @@ import java.awt.*; import java.awt.datatransfer.StringSelection; import java.awt.event.*; import java.io.IOException; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -126,30 +129,19 @@ public class ChatWindow extends JFrame { comp.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); // ContextMenu - Map commands = new HashMap<>() { + Map commands = Map.of("forward selected message", evt -> { + final Message selectedMessage = messageList.getSingleSelectedElement(); + List chosenContacts = ContactsChooserDialog + .showForwardingDialog("Forward selected message to", null, selectedMessage, localDb.getUsers().values()); + if (chosenContacts != null && chosenContacts.size() > 0) forwardMessage(selectedMessage, chosenContacts.toArray(new User[0])); + }, "copy", evt -> { + // TODO should be enhanced to allow also copying of message attachments, + // especially pictures + StringSelection copy = new StringSelection(messageList.getSingleSelectedElement().getText()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); + // TODO insert implementation to edit and delete messages + }, "delete", evt -> {}, "edit", evt -> {}, "quote", evt -> {}); - private static final long serialVersionUID = -2755235774946990126L; - - { - put("forward selected message", evt -> { - final Message selectedMessage = messageList.getSingleSelectedElement(); - forwardMessage(selectedMessage, - ContactsChooserDialog - .showForwardingDialog("Forward selected message to", null, selectedMessage, localDb.getUsers().values()) - .toArray(new User[0])); - }); - put("copy", evt -> { - // TODO should be enhanced to allow also copying of message attachments, - // especially pictures - StringSelection copy = new StringSelection(messageList.getSingleSelectedElement().getText()); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); - }); - // TODO insert implementation to edit and delete messages - put("delete", evt -> {}); - put("edit", evt -> {}); - put("quote", evt -> {}); - } - }; if (isSelected) { contextMenu = new ContextMenu(null, comp, commands, null, null).build(); contextMenu.show(comp, 0, 0); @@ -210,7 +202,7 @@ public class ChatWindow extends JFrame { gbc_messageEnterTextArea.fill = GridBagConstraints.BOTH; gbc_messageEnterTextArea.gridx = 1; gbc_messageEnterTextArea.gridy = 3; - gbc_messageEnterTextArea.insets = insets; + gbc_messageEnterTextArea.insets = insets; contentPane.add(messageEnterTextArea, gbc_messageEnterTextArea); // Post Button @@ -218,7 +210,7 @@ public class ChatWindow extends JFrame { gbc_postButton.fill = GridBagConstraints.BOTH; gbc_postButton.gridx = 2; gbc_postButton.gridy = 3; - gbc_postButton.insets = insets; + gbc_postButton.insets = insets; postButton.addActionListener((evt) -> { postMessage(); }); postButton.setEnabled(false); contentPane.add(postButton, gbc_postButton); diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java index b507cbc..5832e25 100755 --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -18,6 +18,7 @@ import envoy.client.ui.Theme; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentList.SelectionMode; import envoy.client.ui.list.Model; +import envoy.client.ui.list_component.UserComponent; import envoy.data.Message; import envoy.data.User; @@ -35,7 +36,8 @@ public class ContactsChooserDialog extends JDialog { private static final long serialVersionUID = -5774558118579032256L; - private ComponentList contactList = new ComponentList().setModel(new Model()); + private ComponentList contactList = new ComponentList().setModel(new Model()) + .setRenderer((list, user) -> new UserComponent(user)); private JButton okButton = new JButton("Ok"); private JButton cancelButton = new JButton("Cancel"); @@ -77,6 +79,7 @@ public class ContactsChooserDialog extends JDialog { dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelectedElements()); dialog.dispose(); }); Model contactListModel = dialog.getContactList().getModel(); users.forEach(contactListModel::add); + dialog.setModalityType(ModalityType.APPLICATION_MODAL); dialog.setVisible(true); dialog.repaint(); dialog.revalidate(); @@ -90,12 +93,16 @@ public class ContactsChooserDialog extends JDialog { */ private ContactsChooserDialog(Component parent) { contactList.setSelectionMode(SelectionMode.MULTIPLE); + contactList.setSelectionHandler((user, comp, isSelected) -> { + final var theme = Settings.getInstance().getCurrentTheme(); + comp.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); + }); // setBounds(100, 100, 450, 300); - setModal(true); setLocationRelativeTo(parent); getContentPane().setLayout(new BorderLayout()); setBackground(theme.getBackgroundColor()); setForeground(theme.getTextColor()); + setSize(400, 400); contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); getContentPane().add(contentPanel, BorderLayout.CENTER); contentPanel.setLayout(new BorderLayout(0, 0)); @@ -117,6 +124,17 @@ public class ContactsChooserDialog extends JDialog { buttonPane.add(cancelButton, BorderLayout.WEST); } } + applyTheme(Settings.getInstance().getCurrentTheme()); + } + + private void applyTheme(Theme theme) { + contentPanel.setBackground(theme.getBackgroundColor()); + contentPanel.setForeground(theme.getTextColor()); + contactList.setBackground(theme.getCellColor()); + okButton.setBackground(theme.getInteractableBackgroundColor()); + okButton.setForeground(theme.getTextColor()); + cancelButton.setBackground(theme.getInteractableBackgroundColor()); + cancelButton.setForeground(theme.getTextColor()); } /** diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 68b92a2..c8ff3c0 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -83,17 +83,18 @@ public class ComponentList extends JPanel { */ public void selectElement(int index) { final JComponent element = getComponent(index); - if (selection.contains(index)) { - // Remove selection of element at index + // Deselect if clicked again if (selectionHandler != null) selectionHandler.selectionChanged(model.get(index), element, true); selection.remove(index); + } else { // Remove old selection if single selection is enabled if (selectionMode == SelectionMode.SINGLE) clearSelection(); + // Select item if (selectionMode != SelectionMode.NONE) { // Assign new selection From ec341e8518db81e851bce7250678fa0b67f3f935 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Mar 2020 21:28:00 +0100 Subject: [PATCH 288/474] Finalized forwarding UI --- .../ui/container/ContactsChooserDialog.java | 21 +++++++++---------- .../ui/list_component/UserComponent.java | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java index 5832e25..3aa44cd 100755 --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -71,19 +71,19 @@ public class ContactsChooserDialog extends JDialog { dialog.setTitle(title); dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE); dialog.addCancelButtonActionListener(e -> dialog.dispose()); - // dialog.getContentPanel() - // .add(new - // MessageListRenderer(client.getSender().getId()).getListCellComponent(null, - // message, false), BorderLayout.NORTH); + List results = new ArrayList<>(); - dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelectedElements()); dialog.dispose(); }); + dialog.addOkButtonActionListener(e -> { + results.addAll(dialog.getContactList().getSelectedElements()); + dialog.dispose(); + }); Model contactListModel = dialog.getContactList().getModel(); users.forEach(contactListModel::add); + dialog.setModalityType(ModalityType.APPLICATION_MODAL); dialog.setVisible(true); - dialog.repaint(); - dialog.revalidate(); - return results.size() > 0 ? results : null; + + return results; } /** @@ -97,7 +97,6 @@ public class ContactsChooserDialog extends JDialog { final var theme = Settings.getInstance().getCurrentTheme(); comp.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); }); - // setBounds(100, 100, 450, 300); setLocationRelativeTo(parent); getContentPane().setLayout(new BorderLayout()); setBackground(theme.getBackgroundColor()); @@ -111,7 +110,7 @@ public class ContactsChooserDialog extends JDialog { JPanel buttonPane = new JPanel(); getContentPane().add(buttonPane, BorderLayout.SOUTH); { - JButton okButton = new JButton("OK"); + okButton = new JButton("OK"); okButton.setMnemonic(KeyEvent.VK_ENTER); okButton.setActionCommand("OK"); buttonPane.setLayout(new BorderLayout(0, 0)); @@ -119,7 +118,7 @@ public class ContactsChooserDialog extends JDialog { getRootPane().setDefaultButton(okButton); } { - JButton cancelButton = new JButton("Cancel"); + cancelButton = new JButton("Cancel"); cancelButton.setActionCommand("Cancel"); buttonPane.add(cancelButton, BorderLayout.WEST); } diff --git a/src/main/java/envoy/client/ui/list_component/UserComponent.java b/src/main/java/envoy/client/ui/list_component/UserComponent.java index 4a9fbc7..ff60222 100644 --- a/src/main/java/envoy/client/ui/list_component/UserComponent.java +++ b/src/main/java/envoy/client/ui/list_component/UserComponent.java @@ -3,8 +3,8 @@ package envoy.client.ui.list_component; import java.awt.BorderLayout; import java.awt.Dimension; -import javax.swing.JComponent; import javax.swing.JLabel; +import javax.swing.JPanel; import envoy.client.data.Settings; import envoy.client.ui.Color; @@ -22,7 +22,7 @@ import envoy.data.User.UserStatus; * @author Kai S. K. Engelbart * @since Envoy v0.1-beta */ -public class UserComponent extends JComponent { +public class UserComponent extends JPanel { private static final long serialVersionUID = 8450602172939729585L; From 3e48d5862857e6ca196ac16f2529ef243a5fddca Mon Sep 17 00:00:00 2001 From: delvh Date: Mon, 23 Mar 2020 21:35:55 +0100 Subject: [PATCH 289/474] Added theme support for ContextMenu --- .../client/ui/container/ContextMenu.java | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/java/envoy/client/ui/container/ContextMenu.java b/src/main/java/envoy/client/ui/container/ContextMenu.java index facfe73..4624223 100755 --- a/src/main/java/envoy/client/ui/container/ContextMenu.java +++ b/src/main/java/envoy/client/ui/container/ContextMenu.java @@ -10,6 +10,7 @@ import java.util.Map; import javax.swing.*; +import envoy.client.data.Settings; import envoy.client.ui.Theme; /** @@ -60,7 +61,10 @@ public class ContextMenu extends JPopupMenu { * {@link ContextMenu} * @since Envoy v0.1-beta */ - public ContextMenu(Component parent) { setInvoker(parent); } + public ContextMenu(Component parent) { + setInvoker(parent); + setOpaque(true); + } /** * @param label the string that a UI may use to display as a title @@ -80,13 +84,23 @@ public class ContextMenu extends JPopupMenu { */ public ContextMenu(String label, Component parent, Map itemsWithActions, Map itemIcons, Map itemMnemonics) { - super(label); + this(label); setInvoker(parent); this.items = (itemsWithActions != null) ? itemsWithActions : items; this.icons = (itemIcons != null) ? itemIcons : icons; this.mnemonics = (itemMnemonics != null) ? itemMnemonics : mnemonics; } + /** + * @param label the string that a UI may use to display as a title for the + * pop-up menu. + * @since Envoy v0.1-beta + */ + public ContextMenu(String label) { + super(label); + setOpaque(true); + } + /** * Prepares the PopupMenu to be displayed. Should only be used once all map * values have been set. @@ -110,21 +124,16 @@ public class ContextMenu extends JPopupMenu { else // normal JMenuItem wanted item = new JMenuItem(text, icons.containsKey(text) ? icons.get(text) : null); item.addActionListener(action); + item.setOpaque(true); if (mnemonics.containsKey(text)) item.setMnemonic(mnemonics.get(text)); add(item); }); getInvoker().addMouseListener(getShowingListener()); + applyTheme(Settings.getInstance().getCurrentTheme()); built = true; return this; } - /** - * @param label the string that a UI may use to display as a title for the - * pop-up menu. - * @since Envoy v0.1-beta - */ - public ContextMenu(String label) { super(label); } - private MouseAdapter getShowingListener() { return new MouseAdapter() { @@ -240,7 +249,7 @@ public class ContextMenu extends JPopupMenu { * @since Envoy v0.1-beta */ protected void applyTheme(Theme theme) { - setBackground(theme.getInteractableBackgroundColor()); + setBackground(theme.getCellColor()); setForeground(theme.getTextColor()); } } From 37f5a1c5492317a9a914a938f7abb3878cdcec0e Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Mar 2020 21:52:33 +0100 Subject: [PATCH 290/474] Normalized since tags to fit envoy-common and envoy-server Envoy vXXX -> Envoy Client vXXX --- src/main/java/envoy/client/Startup.java | 4 +- src/main/java/envoy/client/data/Cache.java | 8 ++-- src/main/java/envoy/client/data/Chat.java | 14 +++---- .../java/envoy/client/data/ClientConfig.java | 26 ++++++------ src/main/java/envoy/client/data/LocalDb.java | 36 ++++++++--------- .../envoy/client/data/PersistentLocalDb.java | 8 ++-- src/main/java/envoy/client/data/Settings.java | 30 +++++++------- .../java/envoy/client/data/SettingsItem.java | 26 ++++++------ .../envoy/client/data/TransientLocalDb.java | 2 +- .../java/envoy/client/data/package-info.java | 2 +- .../event/HandshakeSuccessfulEvent.java | 2 +- .../client/event/MessageCreationEvent.java | 2 +- .../event/MessageModificationEvent.java | 2 +- .../java/envoy/client/event/SendEvent.java | 2 +- .../envoy/client/event/ThemeChangeEvent.java | 4 +- .../java/envoy/client/event/package-info.java | 2 +- src/main/java/envoy/client/net/Client.java | 20 +++++----- .../MessageStatusChangeEventProcessor.java | 4 +- .../client/net/ReceivedMessageProcessor.java | 2 +- src/main/java/envoy/client/net/Receiver.java | 2 +- .../client/net/UserStatusChangeProcessor.java | 4 +- .../java/envoy/client/net/WriteProxy.java | 10 ++--- .../java/envoy/client/net/package-info.java | 2 +- src/main/java/envoy/client/ui/Color.java | 6 +-- .../java/envoy/client/ui/ContextMenu.java | 24 +++++------ src/main/java/envoy/client/ui/IconUtil.java | 6 +-- .../java/envoy/client/ui/StatusTrayIcon.java | 6 +-- src/main/java/envoy/client/ui/Theme.java | 28 ++++++------- .../envoy/client/ui/container/ChatWindow.java | 16 ++++---- .../ui/container/ContactsChooserDialog.java | 8 ++-- .../client/ui/container/ContextMenu.java | 30 +++++++------- .../client/ui/container/LoginDialog.java | 8 ++-- .../client/ui/container/package-info.java | 2 +- .../envoy/client/ui/list/ComponentList.java | 40 +++++++++---------- src/main/java/envoy/client/ui/list/Model.java | 16 ++++---- .../java/envoy/client/ui/list/Renderer.java | 4 +- .../client/ui/list/SelectionHandler.java | 4 +- .../envoy/client/ui/list/package-info.java | 2 +- .../ContactSearchComponent.java | 4 +- .../ui/list_component/MessageComponent.java | 4 +- .../ui/list_component/UserComponent.java | 4 +- .../ui/list_component/package-info.java | 2 +- .../java/envoy/client/ui/package-info.java | 2 +- .../client/ui/primary/PrimaryButton.java | 2 +- .../client/ui/primary/PrimaryScrollBar.java | 2 +- .../client/ui/primary/PrimaryScrollPane.java | 8 ++-- .../client/ui/primary/PrimaryTextArea.java | 2 +- .../ui/primary/PrimaryToggleSwitch.java | 4 +- .../envoy/client/ui/primary/package-info.java | 2 +- .../client/ui/renderer/UserListRenderer.java | 2 +- .../client/ui/renderer/package-info.java | 2 +- .../ui/settings/GeneralSettingsPanel.java | 4 +- .../client/ui/settings/NewThemeScreen.java | 4 +- .../client/ui/settings/SettingsPanel.java | 2 +- .../client/ui/settings/SettingsScreen.java | 4 +- .../ui/settings/ThemeCustomizationPanel.java | 4 +- .../client/ui/settings/package-info.java | 2 +- src/main/java/module-info.java | 2 +- 58 files changed, 238 insertions(+), 238 deletions(-) diff --git a/src/main/java/envoy/client/Startup.java b/src/main/java/envoy/client/Startup.java index 012b1e8..e4e4667 100644 --- a/src/main/java/envoy/client/Startup.java +++ b/src/main/java/envoy/client/Startup.java @@ -34,7 +34,7 @@ import envoy.util.EnvoyLog; * @author Leon Hofmeister * @author Maximilian Käfer * @author Kai S. K. Engelbart - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public class Startup { @@ -51,7 +51,7 @@ public class Startup { * * @param args the command line arguments may contain configuration parameters * and are parsed by the {@link Config} class - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public static void main(String[] args) { ClientConfig config = ClientConfig.getInstance(); diff --git a/src/main/java/envoy/client/data/Cache.java b/src/main/java/envoy/client/data/Cache.java index 2622322..38d8d24 100644 --- a/src/main/java/envoy/client/data/Cache.java +++ b/src/main/java/envoy/client/data/Cache.java @@ -17,7 +17,7 @@ import envoy.util.EnvoyLog; * * @param the type of cached elements * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class Cache implements Consumer, Serializable { @@ -31,7 +31,7 @@ public class Cache implements Consumer, Serializable { * Adds an element to the cache. * * @param element the element to add - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ @Override public void accept(T element) { @@ -43,7 +43,7 @@ public class Cache implements Consumer, Serializable { * Sets the processor to which cached elements are relayed. * * @param processor the processor to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void setProcessor(Consumer processor) { this.processor = processor; } @@ -51,7 +51,7 @@ public class Cache implements Consumer, Serializable { * Relays all cached elements to the processor. * * @throws IllegalStateException if the processor is not initialized - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void relay() { if (processor == null) throw new IllegalStateException("Processor is not defined"); diff --git a/src/main/java/envoy/client/data/Chat.java b/src/main/java/envoy/client/data/Chat.java index dadeaaa..c41b7db 100644 --- a/src/main/java/envoy/client/data/Chat.java +++ b/src/main/java/envoy/client/data/Chat.java @@ -21,7 +21,7 @@ import envoy.event.MessageStatusChangeEvent; * @author Maximilian Käfer * @author Leon Hofmeister * @author Kai S. K. Engelbart - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public class Chat implements Serializable { @@ -35,7 +35,7 @@ public class Chat implements Serializable { * Saves the Messages in the corresponding chat at that Point. * * @param recipient the user who receives the messages - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public Chat(User recipient) { this.recipient = recipient; } @@ -43,7 +43,7 @@ public class Chat implements Serializable { * Appends a message to the bottom of this chat * * @param message the message to append - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public void appendMessage(Message message) { model.add(message); } @@ -56,7 +56,7 @@ public class Chat implements Serializable { * the message status changes * @throws IOException if a {@link MessageStatusChangeEvent} could not be * delivered to the server - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void read(WriteProxy writeProxy) throws IOException { for (int i = model.size() - 1; i >= 0; --i) { @@ -72,19 +72,19 @@ public class Chat implements Serializable { /** * @return {@code true} if the newest message received in the chat doesn't have * the status {@code READ} - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public boolean isUnread() { return !model.isEmpty() && model.get(model.size() - 1).getStatus() != MessageStatus.READ; } /** * @return all messages in the current chat - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public Model getModel() { return model; } /** * @return the recipient of a message - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public User getRecipient() { return recipient; } } diff --git a/src/main/java/envoy/client/data/ClientConfig.java b/src/main/java/envoy/client/data/ClientConfig.java index 349fa54..63381a0 100644 --- a/src/main/java/envoy/client/data/ClientConfig.java +++ b/src/main/java/envoy/client/data/ClientConfig.java @@ -18,7 +18,7 @@ import envoy.data.LoginCredentials; * Created: 01.03.2020
* * @author Kai S. K. Engelbart - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public class ClientConfig extends Config { @@ -26,7 +26,7 @@ public class ClientConfig extends Config { /** * @return the singleton instance of the client config - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public static ClientConfig getInstance() { if (config == null) config = new ClientConfig(); @@ -47,68 +47,68 @@ public class ClientConfig extends Config { /** * @return the host name of the Envoy server - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public String getServer() { return (String) items.get("server").get(); } /** * @return the port at which the Envoy server is located on the host - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public Integer getPort() { return (Integer) items.get("port").get(); } /** * @return the local database specific to the client user - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public File getLocalDB() { return (File) items.get("localDB").get(); } /** * @return {@code true} if the local database is to be ignored - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public Boolean isIgnoreLocalDB() { return (Boolean) items.get("ignoreLocalDB").get(); } /** * @return the directory in which all local files are saves - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public File getHomeDirectory() { return (File) items.get("homeDirectory").get(); } /** * @return the minimal {@link Level} to log inside the log file - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Level getFileLevelBarrier() { return (Level) items.get("fileLevelBarrier").get(); } /** * @return the minimal {@link Level} to log inside the console - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Level getConsoleLevelBarrier() { return (Level) items.get("consoleLevelBarrier").get(); } /** * @return the user name - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public String getUser() { return (String) items.get("user").get(); } /** * @return the password - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public char[] getPassword() { return (char[]) items.get("password").get(); } /** * @return {@code true} if user name and password are set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public boolean hasLoginCredentials() { return getUser() != null && getPassword() != null; } /** * @return login credentials for the specified user name and password, without * the registration option - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public LoginCredentials getLoginCredentials() { try { diff --git a/src/main/java/envoy/client/data/LocalDb.java b/src/main/java/envoy/client/data/LocalDb.java index dd1db3a..ace19f9 100644 --- a/src/main/java/envoy/client/data/LocalDb.java +++ b/src/main/java/envoy/client/data/LocalDb.java @@ -16,7 +16,7 @@ import envoy.event.MessageStatusChangeEvent; * Created: 3 Feb 2020
* * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public abstract class LocalDb { @@ -30,7 +30,7 @@ public abstract class LocalDb { /** * Initializes a storage space for a user-specific list of chats. * - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void initializeUserStorage() {} @@ -39,7 +39,7 @@ public abstract class LocalDb { * as well. The message id generator will also be saved if present. * * @throws Exception if the saving process failed - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void save() throws Exception {} @@ -47,7 +47,7 @@ public abstract class LocalDb { * Loads all user data. * * @throws Exception if the loading process failed - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void loadUsers() throws Exception {} @@ -55,21 +55,21 @@ public abstract class LocalDb { * Loads all data of the client user. * * @throws Exception if the loading process failed - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void loadUserData() throws Exception {} /** * Loads the ID generator. Any exception thrown during this process is ignored. * - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void loadIdGenerator() {} /** * @return a {@code Map} of all users stored locally with their * user names as keys - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Map getUsers() { return users; } @@ -81,7 +81,7 @@ public abstract class LocalDb { /** * @return all saved {@link Chat} objects that list the client user as the * sender - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha **/ public List getChats() { return chats; } @@ -92,55 +92,55 @@ public abstract class LocalDb { /** * @return the {@link User} who initialized the local database - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public User getUser() { return user; } /** * @param user the user to set - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void setUser(User user) { this.user = user; } /** * @return the message ID generator - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public IdGenerator getIdGenerator() { return idGenerator; } /** * @param idGenerator the message ID generator to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void setIdGenerator(IdGenerator idGenerator) { this.idGenerator = idGenerator; } /** * @return {@code true} if an {@link IdGenerator} is present - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public boolean hasIdGenerator() { return idGenerator != null; } /** * @return the offline message cache - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public Cache getMessageCache() { return messageCache; } /** * @param messageCache the offline message cache to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void setMessageCache(Cache messageCache) { this.messageCache = messageCache; } /** * @return the offline status cache - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public Cache getStatusCache() { return statusCache; } /** * @param statusCache the offline status cache to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void setStatusCache(Cache statusCache) { this.statusCache = statusCache; } @@ -150,7 +150,7 @@ public abstract class LocalDb { * @param id the ID of the message to search for * @return the message with the corresponding ID, or {@code null} if no message * has been found - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Message getMessage(long id) { for (Chat c : chats) diff --git a/src/main/java/envoy/client/data/PersistentLocalDb.java b/src/main/java/envoy/client/data/PersistentLocalDb.java index 52d5c63..2bfb23e 100644 --- a/src/main/java/envoy/client/data/PersistentLocalDb.java +++ b/src/main/java/envoy/client/data/PersistentLocalDb.java @@ -19,7 +19,7 @@ import envoy.util.SerializationUtils; * * @author Kai S. K. Engelbart * @author Maximilian Käfer - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public class PersistentLocalDb extends LocalDb { @@ -32,7 +32,7 @@ public class PersistentLocalDb extends LocalDb { * This constructor shall be used in conjunction with the {@code ignoreLocalDB} * {@link ConfigItem}. * - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public PersistentLocalDb() {} @@ -42,7 +42,7 @@ public class PersistentLocalDb extends LocalDb { * * @param localDbDir the directory in which to store users and chats * @throws IOException if the PersistentLocalDb could not be initialized - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public PersistentLocalDb(File localDbDir) throws IOException { localDBDir = localDbDir; @@ -58,7 +58,7 @@ public class PersistentLocalDb extends LocalDb { * Creates a database file for a user-specific list of chats. * * @throws NullPointerException if the client user is not yet specified - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ @Override public void initializeUserStorage() { diff --git a/src/main/java/envoy/client/data/Settings.java b/src/main/java/envoy/client/data/Settings.java index fd0170c..5bff58c 100644 --- a/src/main/java/envoy/client/data/Settings.java +++ b/src/main/java/envoy/client/data/Settings.java @@ -22,7 +22,7 @@ import envoy.util.SerializationUtils; * @author Leon Hofmeister * @author Maximilian Käfer * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class Settings { @@ -49,7 +49,7 @@ public class Settings { * The way to instantiate the settings. * Is set to private to deny other instances of that object. * - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ private Settings() { // Load settings from settings file @@ -81,7 +81,7 @@ public class Settings { * This method is used to ensure that there is only one instance of Settings. * * @return the instance of Settings - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public static Settings getInstance() { return settings; } @@ -90,7 +90,7 @@ public class Settings { * * @throws IOException if an error occurs while saving the themes to the theme * file - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void save() throws IOException { // Save settings to settings file @@ -110,19 +110,19 @@ public class Settings { * Adds new theme to the theme map. * * @param theme the {@link Theme} to add - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void addNewThemeToMap(Theme theme) { getThemes().put(theme.getThemeName(), theme); } /** * @return the name of the currently active {@link Theme} - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public String getCurrentThemeName() { return (String) items.get("currentTheme").get(); } /** * @return the currently active {@link Theme} - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Theme getCurrentTheme() { return getTheme(getCurrentThemeName()); } @@ -130,7 +130,7 @@ public class Settings { * Sets the name of the current {@link Theme}. * * @param themeName the name to set - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void setCurrentTheme(String themeName) { ((SettingsItem) items.get("currentTheme")).set(themeName); } @@ -138,7 +138,7 @@ public class Settings { * @return {@code true}, if pressing the {@code Enter} key suffices to send a * message. Otherwise it has to be pressed in conjunction with the * {@code Control} key. - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Boolean isEnterToSend() { return (Boolean) items.get("enterToSend").get(); } @@ -148,13 +148,13 @@ public class Settings { * @param enterToSend If set to {@code true} a message can be sent by pressing * the {@code Enter} key. Otherwise it has to be pressed in * conjunction with the {@code Control} key. - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void setEnterToSend(boolean enterToSend) { ((SettingsItem) items.get("enterToSend")).set(enterToSend); } /** * @return the current on close mode. - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public Boolean getCurrentOnCloseMode() { return (Boolean) items.get("onCloseMode").get(); } @@ -162,7 +162,7 @@ public class Settings { * Sets the current on close mode. * * @param currentOnCloseMode the on close mode that should be set. - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void setCurrentOnCloseMode(boolean currentOnCloseMode) { ((SettingsItem) items.get("onCloseMode")).set(currentOnCloseMode); } @@ -178,7 +178,7 @@ public class Settings { /** * @return a {@code Map} of all themes with their names as keys - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Map getThemes() { return themes; } @@ -186,14 +186,14 @@ public class Settings { * Sets the {@code Map} of all themes with their names as keys * * @param themes the theme map to set - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void setThemes(Map themes) { this.themes = themes; } /** * @param themeName the name of the {@link Theme} to get * @return the {@link Theme} with the specified name - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public Theme getTheme(String themeName) { return themes.get(themeName); } } diff --git a/src/main/java/envoy/client/data/SettingsItem.java b/src/main/java/envoy/client/data/SettingsItem.java index cd85c71..7b6eea6 100644 --- a/src/main/java/envoy/client/data/SettingsItem.java +++ b/src/main/java/envoy/client/data/SettingsItem.java @@ -19,7 +19,7 @@ import envoy.client.ui.primary.PrimaryToggleSwitch; * * @param the type of this {@link SettingsItem}'s value * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class SettingsItem implements Serializable { @@ -45,7 +45,7 @@ public class SettingsItem implements Serializable { * @param value the default value * @param userFriendlyName the user friendly name (short) * @param description the description (long) - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public SettingsItem(T value, String userFriendlyName, String description) { this(value, componentClasses.get(value.getClass())); @@ -61,7 +61,7 @@ public class SettingsItem implements Serializable { * * @param value the default value * @param componentClass the class of the {@link JComponent} to represent this {@link SettingsItem} with - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public SettingsItem(T value, Class componentClass) { this.value = value; @@ -72,7 +72,7 @@ public class SettingsItem implements Serializable { * @return an instance of the {@link JComponent} that represents this {@link SettingsItem} * @throws ReflectiveOperationException if the component initialization failed * @throws SecurityException if the component initialization failed - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public JComponent getComponent() throws ReflectiveOperationException, SecurityException { if (componentClass == null) throw new NullPointerException("Component class is null"); @@ -81,7 +81,7 @@ public class SettingsItem implements Serializable { /** * @return the value - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public T get() { return value; } @@ -90,7 +90,7 @@ public class SettingsItem implements Serializable { * defined, it will be invoked with this value. * * @param value the value to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void set(T value) { if (changeHandler != null && value != this.value) changeHandler.accept(value); @@ -99,37 +99,37 @@ public class SettingsItem implements Serializable { /** * @return the componentClass - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public Class getComponentClass() { return componentClass; } /** * @param componentClass the componentClass to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void setComponentClass(Class componentClass) { this.componentClass = componentClass; } /** * @return the userFriendlyName - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public String getUserFriendlyName() { return userFriendlyName; } /** * @param userFriendlyName the userFriendlyName to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void setUserFriendlyName(String userFriendlyName) { this.userFriendlyName = userFriendlyName; } /** * @return the description - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public String getDescription() { return description; } /** * @param description the description to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void setDescription(String description) { this.description = description; } @@ -139,7 +139,7 @@ public class SettingsItem implements Serializable { * when the value changes. * * @param changeHandler the changeHandler to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void setChangeHandler(Consumer changeHandler) { this.changeHandler = changeHandler; diff --git a/src/main/java/envoy/client/data/TransientLocalDb.java b/src/main/java/envoy/client/data/TransientLocalDb.java index 433488a..961dfcc 100644 --- a/src/main/java/envoy/client/data/TransientLocalDb.java +++ b/src/main/java/envoy/client/data/TransientLocalDb.java @@ -9,7 +9,7 @@ package envoy.client.data; * Created: 3 Feb 2020
* * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class TransientLocalDb extends LocalDb { } diff --git a/src/main/java/envoy/client/data/package-info.java b/src/main/java/envoy/client/data/package-info.java index 3129027..3455f5d 100644 --- a/src/main/java/envoy/client/data/package-info.java +++ b/src/main/java/envoy/client/data/package-info.java @@ -4,6 +4,6 @@ * @author Kai S. K. Engelbart * @author Leon Hofmeister * @author Maximilian Käfer - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ package envoy.client.data; diff --git a/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java b/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java index 9cafa48..5fdb307 100644 --- a/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java +++ b/src/main/java/envoy/client/event/HandshakeSuccessfulEvent.java @@ -10,7 +10,7 @@ import envoy.event.Event; * Created: 8 Feb 2020
* * @author Leon Hofmeister - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class HandshakeSuccessfulEvent extends Event.Valueless { diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java index 4781943..14e95e0 100644 --- a/src/main/java/envoy/client/event/MessageCreationEvent.java +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -9,7 +9,7 @@ import envoy.event.Event; * Created: 4 Dec 2019
* * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class MessageCreationEvent extends Event { diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java index 8ddaaf0..0deb536 100644 --- a/src/main/java/envoy/client/event/MessageModificationEvent.java +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -9,7 +9,7 @@ import envoy.event.Event; * Created: 4 Dec 2019
* * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class MessageModificationEvent extends Event { diff --git a/src/main/java/envoy/client/event/SendEvent.java b/src/main/java/envoy/client/event/SendEvent.java index 2d95fc8..5d58f3e 100644 --- a/src/main/java/envoy/client/event/SendEvent.java +++ b/src/main/java/envoy/client/event/SendEvent.java @@ -9,7 +9,7 @@ import envoy.event.Event; * * @author: Maximilian Käfer * - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class SendEvent extends Event> { diff --git a/src/main/java/envoy/client/event/ThemeChangeEvent.java b/src/main/java/envoy/client/event/ThemeChangeEvent.java index c164f72..1010927 100644 --- a/src/main/java/envoy/client/event/ThemeChangeEvent.java +++ b/src/main/java/envoy/client/event/ThemeChangeEvent.java @@ -9,7 +9,7 @@ import envoy.event.Event; * Created: 15 Dec 2019
* * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class ThemeChangeEvent extends Event { @@ -20,7 +20,7 @@ public class ThemeChangeEvent extends Event { * of the {@link Theme} currently in use * * @param theme the new currently used {@link Theme} object - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public ThemeChangeEvent(Theme theme) { super(theme); } } diff --git a/src/main/java/envoy/client/event/package-info.java b/src/main/java/envoy/client/event/package-info.java index 58383e0..6886d5c 100644 --- a/src/main/java/envoy/client/event/package-info.java +++ b/src/main/java/envoy/client/event/package-info.java @@ -4,6 +4,6 @@ * @author Kai S. K. Engelbart * @author Leon Hofmeister * @author Maximilian Käfer - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ package envoy.client.event; diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index acd16e5..a877edd 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -30,7 +30,7 @@ import envoy.util.SerializationUtils; * @author Kai S. K. Engelbart * @author Maximilian Käfer * @author Leon Hofmeister - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public class Client implements Closeable { @@ -124,7 +124,7 @@ public class Client implements Closeable { * initialization * @throws IOException if no {@link IdGenerator} is present and none could be * requested from the server - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void initReceiver(LocalDb localDb, Cache receivedMessageCache) throws IOException { checkOnline(); @@ -181,7 +181,7 @@ public class Client implements Closeable { * * @param message the message to send * @throws IOException if the message does not reach the server - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void sendMessage(Message message) throws IOException { writeObject(message); @@ -200,7 +200,7 @@ public class Client implements Closeable { * Requests a new {@link IdGenerator} from the server. * * @throws IOException if the request does not reach the server - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void requestIdGenerator() throws IOException { logger.info("Requesting new id generator..."); @@ -210,7 +210,7 @@ public class Client implements Closeable { /** * @return a {@code Map} of all users on the server with their * user names as keys - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Map getUsers() { checkOnline(); @@ -232,7 +232,7 @@ public class Client implements Closeable { /** * @return the sender object that represents this client. - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public User getSender() { return sender; } @@ -240,7 +240,7 @@ public class Client implements Closeable { * Sets the client user which is used to send messages. * * @param sender the client user to set - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void setSender(User sender) { this.sender = sender; } @@ -251,19 +251,19 @@ public class Client implements Closeable { /** * @return {@code true} if a connection to the server could be established - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public boolean isOnline() { return online; } /** * @return the contacts of this {@link Client} - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public Contacts getContacts() { return contacts; } /** * @param contacts the contacts to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void setContacts(Contacts contacts) { this.contacts = contacts; } } diff --git a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java index 834bcc8..ce53139 100644 --- a/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java +++ b/src/main/java/envoy/client/net/MessageStatusChangeEventProcessor.java @@ -14,7 +14,7 @@ import envoy.util.EnvoyLog; * Created: 4 Feb 2020
* * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class MessageStatusChangeEventProcessor implements Consumer { @@ -25,7 +25,7 @@ public class MessageStatusChangeEventProcessor implements Consumer31.12.2019
* * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class ReceivedMessageProcessor implements Consumer { diff --git a/src/main/java/envoy/client/net/Receiver.java b/src/main/java/envoy/client/net/Receiver.java index d49fd93..bdaf853 100644 --- a/src/main/java/envoy/client/net/Receiver.java +++ b/src/main/java/envoy/client/net/Receiver.java @@ -19,7 +19,7 @@ import envoy.util.SerializationUtils; * Created: 30.12.2019
* * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class Receiver extends Thread { diff --git a/src/main/java/envoy/client/net/UserStatusChangeProcessor.java b/src/main/java/envoy/client/net/UserStatusChangeProcessor.java index 69a36d4..0fffec2 100644 --- a/src/main/java/envoy/client/net/UserStatusChangeProcessor.java +++ b/src/main/java/envoy/client/net/UserStatusChangeProcessor.java @@ -12,7 +12,7 @@ import envoy.event.UserStatusChangeEvent; * Created: 2 Feb 2020
* * @author Leon Hofmeister - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class UserStatusChangeProcessor implements Consumer { @@ -20,7 +20,7 @@ public class UserStatusChangeProcessor implements Consumer6 Feb 2020
* * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class WriteProxy { @@ -36,7 +36,7 @@ public class WriteProxy { * events * @param localDb the local database used to cache messages and message status * change events - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public WriteProxy(Client client, LocalDb localDb) { this.client = client; @@ -68,7 +68,7 @@ public class WriteProxy { * Sends cached {@link Message}s and {@link MessageStatusChangeEvent}s to the * server. * - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void flushCache() { // Send messages @@ -84,7 +84,7 @@ public class WriteProxy { * * @param message the message to send * @throws IOException if the message could not be sent - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void writeMessage(Message message) throws IOException { if (client.isOnline()) client.sendMessage(message); @@ -97,7 +97,7 @@ public class WriteProxy { * * @param evt the event to send * @throws IOException if the event could not be sent - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void writeMessageStatusChangeEvent(MessageStatusChangeEvent evt) throws IOException { if (client.isOnline()) client.sendEvent(evt); diff --git a/src/main/java/envoy/client/net/package-info.java b/src/main/java/envoy/client/net/package-info.java index 5ee0e4e..9c2a79e 100644 --- a/src/main/java/envoy/client/net/package-info.java +++ b/src/main/java/envoy/client/net/package-info.java @@ -4,6 +4,6 @@ * @author Kai S. K. Engelbart * @author Leon Hofmeister * @author Maximilian Käfer - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ package envoy.client.net; diff --git a/src/main/java/envoy/client/ui/Color.java b/src/main/java/envoy/client/ui/Color.java index eabdac5..bb89943 100644 --- a/src/main/java/envoy/client/ui/Color.java +++ b/src/main/java/envoy/client/ui/Color.java @@ -11,7 +11,7 @@ import java.awt.color.ColorSpace; * Created: 23.12.2019
* * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ @SuppressWarnings("javadoc") public class Color extends java.awt.Color { @@ -102,13 +102,13 @@ public class Color extends java.awt.Color { /** * @return the inversion of this {@link Color} by replacing the red, green and * blue values by subtracting them form 255 - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public Color invert() { return new Color(255 - getRed(), 255 - getGreen(), 255 - getBlue()); } /** * @return the hex value of this {@link Color} - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public String toHex() { return String.format("#%02x%02x%02x", getRed(), getGreen(), getBlue()); } } diff --git a/src/main/java/envoy/client/ui/ContextMenu.java b/src/main/java/envoy/client/ui/ContextMenu.java index ff19ac8..c184eb5 100644 --- a/src/main/java/envoy/client/ui/ContextMenu.java +++ b/src/main/java/envoy/client/ui/ContextMenu.java @@ -24,7 +24,7 @@ import javax.swing.*; * Created: 17 Mar 2020
* * @author Leon Hofmeister - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public class ContextMenu extends JPopupMenu { @@ -54,7 +54,7 @@ public class ContextMenu extends JPopupMenu { /** * @param parent the component which will call this * {@link ContextMenu} - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ContextMenu(Component parent) { setInvoker(parent); } @@ -72,7 +72,7 @@ public class ContextMenu extends JPopupMenu { * @param itemMnemonics the keyboard shortcuts that need to be pressed to * automatically execute the {@link JMenuItem} with the * given text - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ContextMenu(String label, Component parent, Map itemsWithActions, Map itemIcons, Map itemMnemonics) { @@ -89,7 +89,7 @@ public class ContextMenu extends JPopupMenu { * * @return this instance of {@link ContextMenu} to allow chaining behind the * constructor - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ContextMenu build() { items.forEach((text, action) -> { @@ -119,7 +119,7 @@ public class ContextMenu extends JPopupMenu { /** * @param label the string that a UI may use to display as a title for the * pop-up menu. - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ContextMenu(String label) { super(label); } @@ -149,7 +149,7 @@ public class ContextMenu extends JPopupMenu { /** * Removes all subcomponents of this menu. * - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public void clear() { removeAll(); @@ -160,33 +160,33 @@ public class ContextMenu extends JPopupMenu { /** * @return the items - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Map getItems() { return items; } /** * @param items the items with the displayed text and the according action to * take once called - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public void setItems(Map items) { this.items = items; } /** * @return the icons - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Map getIcons() { return icons; } /** * @param icons the icons to set - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public void setIcons(Map icons) { this.icons = icons; } /** * @return the mnemonics (the keyboard shortcuts that automatically execute the * command for a {@link JMenuItem} with corresponding text) - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Map getMnemonics() { return mnemonics; } @@ -194,7 +194,7 @@ public class ContextMenu extends JPopupMenu { * @param mnemonics the keyboard shortcuts that need to be pressed to * automatically execute the {@link JMenuItem} with the given * text - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public void setMnemonics(Map mnemonics) { this.mnemonics = mnemonics; } } diff --git a/src/main/java/envoy/client/ui/IconUtil.java b/src/main/java/envoy/client/ui/IconUtil.java index 25d6513..0092483 100644 --- a/src/main/java/envoy/client/ui/IconUtil.java +++ b/src/main/java/envoy/client/ui/IconUtil.java @@ -17,7 +17,7 @@ import javax.swing.ImageIcon; * Created: 16.03.2020 * * @author Kai S. K. Engelbart - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public class IconUtil { @@ -30,7 +30,7 @@ public class IconUtil { * @param size the size to scale the icon to * @return the scaled icon * @throws IOException if the loading process failed - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public static ImageIcon load(String path, int size) throws IOException { return new ImageIcon(ImageIO.read(IconUtil.class.getResourceAsStream(path)).getScaledInstance(size, size, Image.SCALE_SMOOTH)); @@ -49,7 +49,7 @@ public class IconUtil { * @return a map containing the loaded icons with the corresponding enum * constants as keys * @throws IOException if the loading process failed - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public static > EnumMap loadByEnum(Class enumClass, int size) throws IOException { var icons = new EnumMap(enumClass); diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 02e5629..621655f 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -16,7 +16,7 @@ import envoy.exception.EnvoyException; * Created: 3 Dec 2019
* * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class StatusTrayIcon { @@ -41,7 +41,7 @@ public class StatusTrayIcon { * notifications are displayed * @throws EnvoyException if the currently used OS does not support the System * Tray API - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public StatusTrayIcon(Window focusTarget) throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); @@ -85,7 +85,7 @@ public class StatusTrayIcon { * * @throws EnvoyException if the status icon could not be attaches to the system * tray for system-internal reasons - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void show() throws EnvoyException { try { diff --git a/src/main/java/envoy/client/ui/Theme.java b/src/main/java/envoy/client/ui/Theme.java index 9fb8726..96d8357 100755 --- a/src/main/java/envoy/client/ui/Theme.java +++ b/src/main/java/envoy/client/ui/Theme.java @@ -10,7 +10,7 @@ import java.util.Map; * Created: 23 Nov 2019
* * @author Maximilian Käfer - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class Theme implements Serializable { @@ -35,7 +35,7 @@ public class Theme implements Serializable { * @param selectionColor the section color * @param typingMessageColor the color of currently typed messages * @param userNameColor the color of user names - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, Color interactableBackgroundColor, Color textColor, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) { @@ -59,7 +59,7 @@ public class Theme implements Serializable { * * @param name the name of the {@link Theme} * @param other the {@link Theme} to copy - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Theme(String name, Theme other) { themeName = name; @@ -69,69 +69,69 @@ public class Theme implements Serializable { /** * @return a {@code Map} of all colors defined for this theme * with their names as keys - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Map getColors() { return colors; } /** * @return name of the theme - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public String getThemeName() { return themeName; } /** * @return interactableForegroundColor - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Color getInteractableForegroundColor() { return colors.get("interactableForegroundColor"); } /** * @return the {@link Color} in which the text content of a message should be * displayed - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Color getTextColor() { return colors.get("textColor"); } /** * @return the {@link Color} in which the creation date of a message should be * displayed - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Color getDateColor() { return colors.get("dateColorChat"); } /** * @return selectionColor - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Color getSelectionColor() { return colors.get("selectionColor"); } /** * @return typingMessageColor - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Color getTypingMessageColor() { return colors.get("typingMessageColor"); } /** * @return backgroundColor - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Color getBackgroundColor() { return colors.get("backgroundColor"); } /** * @return cellColor - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Color getCellColor() { return colors.get("cellColor"); } /** * @return interactableBackgroundColor - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Color getInteractableBackgroundColor() { return colors.get("interactableBackgroundColor"); } /** * @return userNameColor - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public Color getUserNameColor() { return colors.get("userNameColor"); } diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index 4d92a03..81b155c 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -49,7 +49,7 @@ import envoy.util.EnvoyLog; * @author Kai S. K. Engelbart * @author Maximilian Käfer * @author Leon Hofmeister - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public class ChatWindow extends JFrame { @@ -103,7 +103,7 @@ public class ChatWindow extends JFrame { * Initializes a {@link JFrame} with UI elements used to send and read messages * to different users. * - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public ChatWindow() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -481,7 +481,7 @@ public class ChatWindow extends JFrame { * Used to immediately reload the {@link ChatWindow} when settings were changed. * * @param theme the theme to change colors into - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ private void applyTheme(Theme theme) { // contentPane @@ -532,7 +532,7 @@ public class ChatWindow extends JFrame { /** * Sends a new message to the server based on the text entered in the textArea. * - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ private void postMessage() { if (userList.isSelectionEmpty()) { @@ -557,7 +557,7 @@ public class ChatWindow extends JFrame { * * @param message the message to forward * @param recipient the new recipient of the message - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ private void forwardMessage(Message message, User... recipients) { Arrays.stream(recipients).forEach(recipient -> { @@ -576,7 +576,7 @@ public class ChatWindow extends JFrame { * Sends a {@link Message} to the server. * * @param message the message to send - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ private void sendMessage(final Message message) { try { @@ -639,7 +639,7 @@ public class ChatWindow extends JFrame { * @param writeProxy the write proxy used to send messages and status change * events to the server or cache them inside the local * database - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void initContent(Client client, LocalDb localDb, WriteProxy writeProxy) { this.client = client; @@ -668,7 +668,7 @@ public class ChatWindow extends JFrame { * {@link ChatWindow#MAX_MESSAGE_LENGTH} * and splits the text into the allowed part, if that is the case. * - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ private void checkMessageTextLength() { String input = messageEnterTextArea.getText(); diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java index 3aa44cd..26a099e 100755 --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -30,7 +30,7 @@ import envoy.data.User; * Created: 15 Mar 2020
* * @author Leon Hofmeister - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public class ContactsChooserDialog extends JDialog { @@ -64,7 +64,7 @@ public class ContactsChooserDialog extends JDialog { * @param users the users that should be displayed * @return the selected Element (yet has to be casted to the wanted type due to * the Generics limitations in Java) - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public static List showForwardingDialog(String title, Component parent, Message message, Collection users) { ContactsChooserDialog dialog = new ContactsChooserDialog(parent); @@ -89,7 +89,7 @@ public class ContactsChooserDialog extends JDialog { /** * @param parent this @{@link Component} will be parsed to * {@link java.awt.Window#setLocationRelativeTo(Component)} - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ private ContactsChooserDialog(Component parent) { contactList.setSelectionMode(SelectionMode.MULTIPLE); @@ -138,7 +138,7 @@ public class ContactsChooserDialog extends JDialog { /** * @return the underlying {@link ComponentList} - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ private ComponentList getContactList() { return contactList; } diff --git a/src/main/java/envoy/client/ui/container/ContextMenu.java b/src/main/java/envoy/client/ui/container/ContextMenu.java index 4624223..c52c042 100755 --- a/src/main/java/envoy/client/ui/container/ContextMenu.java +++ b/src/main/java/envoy/client/ui/container/ContextMenu.java @@ -28,7 +28,7 @@ import envoy.client.ui.Theme; * Created: 17 Mar 2020
* * @author Leon Hofmeister - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public class ContextMenu extends JPopupMenu { @@ -59,7 +59,7 @@ public class ContextMenu extends JPopupMenu { /** * @param parent the component which will call this * {@link ContextMenu} - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ContextMenu(Component parent) { setInvoker(parent); @@ -80,7 +80,7 @@ public class ContextMenu extends JPopupMenu { * @param itemMnemonics the keyboard shortcuts that need to be pressed to * automatically execute the {@link JMenuItem} with the * given text - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ContextMenu(String label, Component parent, Map itemsWithActions, Map itemIcons, Map itemMnemonics) { @@ -94,7 +94,7 @@ public class ContextMenu extends JPopupMenu { /** * @param label the string that a UI may use to display as a title for the * pop-up menu. - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ContextMenu(String label) { super(label); @@ -107,7 +107,7 @@ public class ContextMenu extends JPopupMenu { * * @return this instance of {@link ContextMenu} to allow chaining behind the * constructor - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ContextMenu build() { items.forEach((text, action) -> { @@ -162,7 +162,7 @@ public class ContextMenu extends JPopupMenu { /** * Removes all subcomponents of this menu. * - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public void clear() { removeAll(); @@ -173,33 +173,33 @@ public class ContextMenu extends JPopupMenu { /** * @return the items - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Map getItems() { return items; } /** * @param items the items with the displayed text and the according action to * take once called - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public void setItems(Map items) { this.items = items; } /** * @return the icons - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Map getIcons() { return icons; } /** * @param icons the icons to set - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public void setIcons(Map icons) { this.icons = icons; } /** * @return the mnemonics (the keyboard shortcuts that automatically execute the * command for a {@link JMenuItem} with corresponding text) - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Map getMnemonics() { return mnemonics; } @@ -207,7 +207,7 @@ public class ContextMenu extends JPopupMenu { * @param mnemonics the keyboard shortcuts that need to be pressed to * automatically execute the {@link JMenuItem} with the given * text - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public void setMnemonics(Map mnemonics) { this.mnemonics = mnemonics; } @@ -216,7 +216,7 @@ public class ContextMenu extends JPopupMenu { * Additionally sets the foreground of all subcomponents of this * {@link ContextMenu}. * - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ @Override public void setForeground(Color color) { @@ -230,7 +230,7 @@ public class ContextMenu extends JPopupMenu { * Additionally sets the background of all subcomponents of this * {@link ContextMenu}. * - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ @Override public void setBackground(Color color) { @@ -246,7 +246,7 @@ public class ContextMenu extends JPopupMenu { * Envoy-exclusive object. * * @param theme the theme to use - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ protected void applyTheme(Theme theme) { setBackground(theme.getCellColor()); diff --git a/src/main/java/envoy/client/ui/container/LoginDialog.java b/src/main/java/envoy/client/ui/container/LoginDialog.java index 8780358..23c0113 100644 --- a/src/main/java/envoy/client/ui/container/LoginDialog.java +++ b/src/main/java/envoy/client/ui/container/LoginDialog.java @@ -33,7 +33,7 @@ import envoy.util.EnvoyLog; * * @author Kai S. K. Engelbart * @author Maximilian Käfer - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class LoginDialog extends JDialog { @@ -74,7 +74,7 @@ public class LoginDialog extends JDialog { * @param localDb the local database in which data is persisted * @param receivedMessageCache the cache that stored messages received during * the handshake - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public LoginDialog(Client client, LocalDb localDb, Cache receivedMessageCache) { this.client = client; @@ -283,7 +283,7 @@ public class LoginDialog extends JDialog { /** * Resets the text stored in the password fields. * - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ private void clearPasswordFields() { passwordField.setText(null); @@ -337,7 +337,7 @@ public class LoginDialog extends JDialog { /** * Shuts the system down properly if the login was aborted. * - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ private void abortLogin() { logger.info("The login process has been cancelled. Exiting..."); diff --git a/src/main/java/envoy/client/ui/container/package-info.java b/src/main/java/envoy/client/ui/container/package-info.java index 27645f4..aab40a5 100644 --- a/src/main/java/envoy/client/ui/container/package-info.java +++ b/src/main/java/envoy/client/ui/container/package-info.java @@ -8,6 +8,6 @@ * @author Leon Hofmeister * @author Kai S. K. Engelbart * @author Maximilian Käfer - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ package envoy.client.ui.container; diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index c8ff3c0..f2de2c3 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -19,7 +19,7 @@ import javax.swing.*; * * @param the type of object displayed in this list * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class ComponentList extends JPanel { @@ -34,7 +34,7 @@ public class ComponentList extends JPanel { /** * Defines the possible modes of selection that can be performed by the user * - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public static enum SelectionMode { /** @@ -56,7 +56,7 @@ public class ComponentList extends JPanel { /** * Creates an instance of {@link ComponentList}. * - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public ComponentList() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); } @@ -64,7 +64,7 @@ public class ComponentList extends JPanel { * Removes all child components and then adds all components representing the * elements of the {@link Model}. * - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void synchronizeModel() { if (model != null) { @@ -79,7 +79,7 @@ public class ComponentList extends JPanel { * removed from the selection. * * @param index the index of the selected component - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public void selectElement(int index) { final JComponent element = getComponent(index); @@ -112,7 +112,7 @@ public class ComponentList extends JPanel { /** * Removes the current selection. * - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public void clearSelection() { if (selectionHandler != null) selection.forEach(i -> selectionHandler.selectionChanged(model.get(i), getComponent(i), false)); @@ -124,7 +124,7 @@ public class ComponentList extends JPanel { * {@link Renderer}. * * @param elem the element to add - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ void addElement(E elem) { if (renderer != null) { @@ -140,7 +140,7 @@ public class ComponentList extends JPanel { * @return a mouse listener calling the * {@link ComponentList#selectElement(int)} method with the * component's index when a left click is performed by the user - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ private MouseListener getSelectionListener(int componentIndex) { return new MouseAdapter() { @@ -155,13 +155,13 @@ public class ComponentList extends JPanel { /** * @return a set of all selected indices - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Set getSelection() { return selection; } /** * @return a set of all selected elements - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Set getSelectedElements() { var selectedElements = new HashSet(); @@ -172,20 +172,20 @@ public class ComponentList extends JPanel { /** * @return the index of an arbitrary selected element * @throws java.util.NoSuchElementException if no selection is present - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public int getSingleSelection() { return selection.stream().findAny().get(); } /** * @return an arbitrary selected element * @throws java.util.NoSuchElementException if no selection is present - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public E getSingleSelectedElement() { return model.get(getSingleSelection()); } /** * @return the model - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Model getModel() { return model; } @@ -196,7 +196,7 @@ public class ComponentList extends JPanel { * * @param model the list model to set * @return this component list - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public ComponentList setModel(Model model) { @@ -213,14 +213,14 @@ public class ComponentList extends JPanel { /** * @return the renderer - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public Renderer getRenderer() { return renderer; } /** * @param renderer the renderer to set * @return this component list - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ComponentList setRenderer(Renderer renderer) { this.renderer = renderer; @@ -229,7 +229,7 @@ public class ComponentList extends JPanel { /** * @return the selection mode - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public SelectionMode getSelectionMode() { return selectionMode; } @@ -239,7 +239,7 @@ public class ComponentList extends JPanel { * * @param selectionMode the selection mode to set * @return this component list - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ComponentList setSelectionMode(SelectionMode selectionMode) { this.selectionMode = selectionMode; @@ -249,13 +249,13 @@ public class ComponentList extends JPanel { /** * @return the selection handler - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public SelectionHandler getSelectionHandler() { return selectionHandler; } /** * @param selectionHandler the selection handler to set - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public void setSelectionHandler(SelectionHandler selectionHandler) { this.selectionHandler = selectionHandler; } } diff --git a/src/main/java/envoy/client/ui/list/Model.java b/src/main/java/envoy/client/ui/list/Model.java index 6dca5eb..4f13636 100644 --- a/src/main/java/envoy/client/ui/list/Model.java +++ b/src/main/java/envoy/client/ui/list/Model.java @@ -14,7 +14,7 @@ import java.util.List; * * @param the type of object displayed in this list * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public final class Model implements Iterable, Serializable { @@ -30,7 +30,7 @@ public final class Model implements Iterable, Serializable { * @param e the element to add * @return {@code true} * @see java.util.List#add(java.lang.Object) - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public boolean add(E e) { if (componentList != null) { @@ -45,7 +45,7 @@ public final class Model implements Iterable, Serializable { * {@link ComponentList}. * * @see java.util.List#clear() - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public void clear() { elements.clear(); @@ -56,7 +56,7 @@ public final class Model implements Iterable, Serializable { * @param index the index to retrieve the element from * @return the element located at the index * @see java.util.List#get(int) - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public E get(int index) { return elements.get(index); } @@ -67,7 +67,7 @@ public final class Model implements Iterable, Serializable { * @param index the index of the element to remove * @return the removed element * @see java.util.List#remove(int) - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public E remove(int index) { if (componentList != null) componentList.remove(index); @@ -77,7 +77,7 @@ public final class Model implements Iterable, Serializable { /** * @return the amount of elements in this list model * @see java.util.List#size() - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public int size() { return elements.size(); } @@ -90,7 +90,7 @@ public final class Model implements Iterable, Serializable { /** * @return an iterator over the elements of this list model * @see java.util.List#iterator() - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ @Override public Iterator iterator() { @@ -111,7 +111,7 @@ public final class Model implements Iterable, Serializable { * synchronization. * * @param componentList the component list to set - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ void setComponentList(ComponentList componentList) { this.componentList = componentList; diff --git a/src/main/java/envoy/client/ui/list/Renderer.java b/src/main/java/envoy/client/ui/list/Renderer.java index 58e6ad9..f2d3ad9 100644 --- a/src/main/java/envoy/client/ui/list/Renderer.java +++ b/src/main/java/envoy/client/ui/list/Renderer.java @@ -12,7 +12,7 @@ import javax.swing.JComponent; * * @param the type of object displayed in this list * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ @FunctionalInterface public interface Renderer { @@ -25,7 +25,7 @@ public interface Renderer { * @param isSelected {@code true} if the user has selected the list cell in * which the list element is rendered * @return the component representing the list element - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ JComponent getListCellComponent(ComponentList list, E value); } diff --git a/src/main/java/envoy/client/ui/list/SelectionHandler.java b/src/main/java/envoy/client/ui/list/SelectionHandler.java index 998bee2..d8c1984 100644 --- a/src/main/java/envoy/client/ui/list/SelectionHandler.java +++ b/src/main/java/envoy/client/ui/list/SelectionHandler.java @@ -11,7 +11,7 @@ import javax.swing.JComponent; * * @author Kai S. K. Engelbart * @param the type of the underlying {@link ComponentList} - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ @FunctionalInterface public interface SelectionHandler { @@ -22,7 +22,7 @@ public interface SelectionHandler { * @param element the selected element * @param component the selected component * @param isSelected contains the selection state - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ void selectionChanged(E element, JComponent component, boolean isSelected); } diff --git a/src/main/java/envoy/client/ui/list/package-info.java b/src/main/java/envoy/client/ui/list/package-info.java index 5f12ffd..50d553b 100644 --- a/src/main/java/envoy/client/ui/list/package-info.java +++ b/src/main/java/envoy/client/ui/list/package-info.java @@ -5,6 +5,6 @@ * @author Kai S. K. Engelbart * @author Leon Hofmeister * @author Maximilian Käfer - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ package envoy.client.ui.list; diff --git a/src/main/java/envoy/client/ui/list_component/ContactSearchComponent.java b/src/main/java/envoy/client/ui/list_component/ContactSearchComponent.java index 16acaa4..9f66506 100644 --- a/src/main/java/envoy/client/ui/list_component/ContactSearchComponent.java +++ b/src/main/java/envoy/client/ui/list_component/ContactSearchComponent.java @@ -20,7 +20,7 @@ import envoy.event.EventBus; * Created: 21.03.2020 * * @author Kai S. K. Engelbart - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public class ContactSearchComponent extends JComponent { @@ -29,7 +29,7 @@ public class ContactSearchComponent extends JComponent { /** * @param list the {@link ComponentList} that is used to display search results * @param user the {@link User} that appears as a search result - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public ContactSearchComponent(ComponentList list, User user) { setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); diff --git a/src/main/java/envoy/client/ui/list_component/MessageComponent.java b/src/main/java/envoy/client/ui/list_component/MessageComponent.java index 4b6ca83..abe436c 100644 --- a/src/main/java/envoy/client/ui/list_component/MessageComponent.java +++ b/src/main/java/envoy/client/ui/list_component/MessageComponent.java @@ -22,7 +22,7 @@ import envoy.data.User; * Created: 21.03.2020 * * @author Kai S. K. Engelbart - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public class MessageComponent extends JPanel { @@ -45,7 +45,7 @@ public class MessageComponent extends JPanel { * @param message the {@link Message} to display * @param senderId the id of the {@link User} who sends messages from this * account - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public MessageComponent(ComponentList list, Message message, long senderId) { var width = list.getMaximumSize().width; diff --git a/src/main/java/envoy/client/ui/list_component/UserComponent.java b/src/main/java/envoy/client/ui/list_component/UserComponent.java index ff60222..7eebfdf 100644 --- a/src/main/java/envoy/client/ui/list_component/UserComponent.java +++ b/src/main/java/envoy/client/ui/list_component/UserComponent.java @@ -20,7 +20,7 @@ import envoy.data.User.UserStatus; * Created: 21.03.2020 * * @author Kai S. K. Engelbart - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public class UserComponent extends JPanel { @@ -28,7 +28,7 @@ public class UserComponent extends JPanel { /** * @param user the {@link User} whose information is displayed - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ public UserComponent(User user) { final Theme theme = Settings.getInstance().getCurrentTheme(); diff --git a/src/main/java/envoy/client/ui/list_component/package-info.java b/src/main/java/envoy/client/ui/list_component/package-info.java index 053d2bd..89da45c 100644 --- a/src/main/java/envoy/client/ui/list_component/package-info.java +++ b/src/main/java/envoy/client/ui/list_component/package-info.java @@ -9,6 +9,6 @@ * @author Leon Hofmeister * @author Kai S. K. Engelbart * @author Maximilian Käfer - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ package envoy.client.ui.list_component; diff --git a/src/main/java/envoy/client/ui/package-info.java b/src/main/java/envoy/client/ui/package-info.java index 22238af..10bf4ee 100644 --- a/src/main/java/envoy/client/ui/package-info.java +++ b/src/main/java/envoy/client/ui/package-info.java @@ -4,6 +4,6 @@ * @author Kai S. K. Engelbart * @author Leon Hofmeister * @author Maximilian Käfer - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ package envoy.client.ui; diff --git a/src/main/java/envoy/client/ui/primary/PrimaryButton.java b/src/main/java/envoy/client/ui/primary/PrimaryButton.java index efcfd9f..811939f 100644 --- a/src/main/java/envoy/client/ui/primary/PrimaryButton.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryButton.java @@ -11,7 +11,7 @@ import javax.swing.JButton; * * @author Kai S. K. Engelbart * @author Maximilian Käfer - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class PrimaryButton extends JButton { diff --git a/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java index 59846fa..5630525 100644 --- a/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java @@ -16,7 +16,7 @@ import envoy.client.ui.Theme; * Created: 14.12.2019
* * @author Maximilian Käfer - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class PrimaryScrollBar extends BasicScrollBarUI { diff --git a/src/main/java/envoy/client/ui/primary/PrimaryScrollPane.java b/src/main/java/envoy/client/ui/primary/PrimaryScrollPane.java index 47c2abb..a27b075 100644 --- a/src/main/java/envoy/client/ui/primary/PrimaryScrollPane.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryScrollPane.java @@ -22,7 +22,7 @@ public class PrimaryScrollPane extends JScrollPane { /** * Initializes a {@link JScrollPane} with the primary Envoy design scheme * - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public PrimaryScrollPane() { setBorder(null); } @@ -30,7 +30,7 @@ public class PrimaryScrollPane extends JScrollPane { * Styles the vertical and horizontal scroll bars. * * @param theme the color set used to color the component - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void applyTheme(Theme theme) { setForeground(theme.getBackgroundColor()); @@ -54,7 +54,7 @@ public class PrimaryScrollPane extends JScrollPane { * When rereading messages, the chat doesn't scroll down if new messages
* are added. (Besides see first point) * - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void autoscroll() { // Automatic scrolling to the bottom @@ -79,7 +79,7 @@ public class PrimaryScrollPane extends JScrollPane { * triggering it to automatically scroll down. * * @param chatOpened indicates the chat opening status - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public void setChatOpened(boolean chatOpened) { this.chatOpened = chatOpened; } } diff --git a/src/main/java/envoy/client/ui/primary/PrimaryTextArea.java b/src/main/java/envoy/client/ui/primary/PrimaryTextArea.java index 9f6a7ce..280d8e9 100644 --- a/src/main/java/envoy/client/ui/primary/PrimaryTextArea.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryTextArea.java @@ -12,7 +12,7 @@ import javax.swing.border.EmptyBorder; * Created: 07.12.2019
* * @author Maximilian Käfer - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class PrimaryTextArea extends JTextArea { diff --git a/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java index fea465f..d6931f7 100644 --- a/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java @@ -19,7 +19,7 @@ import envoy.client.ui.Color; * * @author Maximilian Käfer * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class PrimaryToggleSwitch extends JButton { @@ -32,7 +32,7 @@ public class PrimaryToggleSwitch extends JButton { * * @param settingsItem the {@link SettingsItem} that is controlled by this * {@link PrimaryToggleSwitch} - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public PrimaryToggleSwitch(SettingsItem settingsItem) { setPreferredSize(new Dimension(50, 25)); diff --git a/src/main/java/envoy/client/ui/primary/package-info.java b/src/main/java/envoy/client/ui/primary/package-info.java index 8ede25f..d4c54fa 100644 --- a/src/main/java/envoy/client/ui/primary/package-info.java +++ b/src/main/java/envoy/client/ui/primary/package-info.java @@ -12,6 +12,6 @@ * @author Leon Hofmeister * @author Kai S. K. Engelbart * @author Maximilian Käfer - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ package envoy.client.ui.primary; diff --git a/src/main/java/envoy/client/ui/renderer/UserListRenderer.java b/src/main/java/envoy/client/ui/renderer/UserListRenderer.java index 89435df..685c61b 100644 --- a/src/main/java/envoy/client/ui/renderer/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/UserListRenderer.java @@ -20,7 +20,7 @@ import envoy.data.User.UserStatus; * * @author Kai S. K. Engelbart * @author Maximilian Käfer - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public class UserListRenderer extends JLabel implements ListCellRenderer { diff --git a/src/main/java/envoy/client/ui/renderer/package-info.java b/src/main/java/envoy/client/ui/renderer/package-info.java index 68748ef..6a6f58e 100644 --- a/src/main/java/envoy/client/ui/renderer/package-info.java +++ b/src/main/java/envoy/client/ui/renderer/package-info.java @@ -9,6 +9,6 @@ * @author Leon Hofmeister * @author Kai S. K. Engelbart * @author Maximilian Käfer - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ package envoy.client.ui.renderer; diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index ce40e91..b194e1c 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -22,7 +22,7 @@ import envoy.util.EnvoyLog; * Created: 21 Dec 2019
* * @author Maximilian Käfer - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class GeneralSettingsPanel extends SettingsPanel { @@ -38,7 +38,7 @@ public class GeneralSettingsPanel extends SettingsPanel { * * @param parent the {@link SettingsScreen} as a part of which this * {@link SettingsPanel} is displayed - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public GeneralSettingsPanel(SettingsScreen parent) { super(parent); diff --git a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java index 906bb91..6c6c273 100644 --- a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java +++ b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java @@ -20,7 +20,7 @@ import envoy.client.ui.primary.PrimaryTextArea; * Created: 26 Dec 2019
* * @author Maximilian Käfer - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public class NewThemeScreen extends JDialog { @@ -48,7 +48,7 @@ public class NewThemeScreen extends JDialog { * @param newThemeAction is executed when a new theme name is entered * @param modifyThemeAction is executed when an existing theme name is entered * and confirmed - * @since Envoy v0.3-alpha + * @since Envoy Client v0.3-alpha */ public NewThemeScreen(SettingsScreen parent, Consumer newThemeAction, Consumer modifyThemeAction) { this.newThemeAction = newThemeAction; diff --git a/src/main/java/envoy/client/ui/settings/SettingsPanel.java b/src/main/java/envoy/client/ui/settings/SettingsPanel.java index 421b774..96be74e 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/SettingsPanel.java @@ -12,7 +12,7 @@ import javax.swing.JPanel; * Created: 20 Dec 2019
* * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public abstract class SettingsPanel extends JPanel { diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 0c98084..ba93270 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -26,7 +26,7 @@ import envoy.util.EnvoyLog; * @author Leon Hofmeister * @author Maximilian Käfer * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class SettingsScreen extends JDialog { @@ -51,7 +51,7 @@ public class SettingsScreen extends JDialog { /** * Initializes the settings screen. * - * @since Envoy v0.1-alpha + * @since Envoy Client v0.1-alpha */ public SettingsScreen() { // Initialize settings pages diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index a68a6a5..fce9754 100755 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -24,7 +24,7 @@ import envoy.util.EnvoyLog; * * @author Kai S. K. Engelbart * @author Maximilian Käfer - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public class ThemeCustomizationPanel extends SettingsPanel { @@ -48,7 +48,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { * * @param parent the {@link SettingsScreen} as a part of which this * {@link SettingsPanel} is displayed - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ public ThemeCustomizationPanel(SettingsScreen parent) { super(parent); diff --git a/src/main/java/envoy/client/ui/settings/package-info.java b/src/main/java/envoy/client/ui/settings/package-info.java index bde6540..5325a73 100644 --- a/src/main/java/envoy/client/ui/settings/package-info.java +++ b/src/main/java/envoy/client/ui/settings/package-info.java @@ -4,6 +4,6 @@ * @author Kai S. K. Engelbart * @author Leon Hofmeister * @author Maximilian Käfer - * @since Envoy v0.2-alpha + * @since Envoy Client v0.2-alpha */ package envoy.client.ui.settings; diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 4227885..d5c969a 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -5,7 +5,7 @@ * @author Kai S. K. Engelbart * @author Leon Hofmeister * @author Maximilian Käfer - * @since Envoy v0.1-beta + * @since Envoy Client v0.1-beta */ module envoy { From ef3ebceb10c60d10798b4a4fef95e5d93c8bf9c9 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 23 Mar 2020 21:56:01 +0100 Subject: [PATCH 291/474] Adjusted envoy-common dependency back to develop-snapshot --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1ffd41f..572b5ed 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - f~forwarding_messages-SNAPSHOT + develop-SNAPSHOT From c5a6978a85bc9b310be4fc4a5c9c8f92e5ee7b29 Mon Sep 17 00:00:00 2001 From: delvh Date: Tue, 24 Mar 2020 18:38:47 +0100 Subject: [PATCH 292/474] Renamed classes with a two-letter initialism according to convention --- .settings/org.eclipse.jdt.ui.prefs | 2 ++ src/main/java/envoy/client/Startup.java | 26 +++++++------- .../data/{LocalDb.java => LocalDB.java} | 4 +-- ...entLocalDb.java => PersistentLocalDB.java} | 14 ++++---- ...ientLocalDb.java => TransientLocalDB.java} | 6 ++-- src/main/java/envoy/client/net/Client.java | 16 ++++----- .../client/net/UserStatusChangeProcessor.java | 10 +++--- .../java/envoy/client/net/WriteProxy.java | 26 +++++++------- .../envoy/client/ui/container/ChatWindow.java | 36 +++++++++---------- .../client/ui/container/LoginDialog.java | 16 ++++----- 10 files changed, 79 insertions(+), 77 deletions(-) rename src/main/java/envoy/client/data/{LocalDb.java => LocalDB.java} (98%) rename src/main/java/envoy/client/data/{PersistentLocalDb.java => PersistentLocalDB.java} (88%) rename src/main/java/envoy/client/data/{TransientLocalDb.java => TransientLocalDB.java} (60%) diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs index cdb456a..62985b5 100644 --- a/.settings/org.eclipse.jdt.ui.prefs +++ b/.settings/org.eclipse.jdt.ui.prefs @@ -1,5 +1,7 @@ eclipse.preferences.version=1 org.eclipse.jdt.ui.ignorelowercasenames=true org.eclipse.jdt.ui.importorder=java;javax;org;com; +org.eclipse.jdt.ui.javadoc=true org.eclipse.jdt.ui.ondemandthreshold=4 org.eclipse.jdt.ui.staticondemandthreshold=2 +org.eclipse.jdt.ui.text.custom_code_templates=