From 6d51b2d5321de102af1e3ae705f5c2ead1dcb8c4 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 24 Sep 2023 07:51:38 +1000 Subject: [PATCH 01/78] Adding passing in functions to the dialogs to be called (optionally) if set. Adding some tests to test the functionality of the functions... --- src/urChatBasic/frontend/UserGUI.java | 3 +- .../frontend/dialogs/MessageDialog.java | 32 +++++- .../frontend/dialogs/YesNoDialog.java | 75 ++++++++++++++ .../tests/backend/DialogTests.java | 97 +++++++++++++++++++ 4 files changed, 203 insertions(+), 4 deletions(-) create mode 100644 src/urChatBasic/frontend/dialogs/YesNoDialog.java create mode 100644 src/urChatBasic/tests/backend/DialogTests.java diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 9810afe..d26748c 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -1718,8 +1718,7 @@ private void setNewLAF(String newLAFname) boolean flatLafAvailable = false; try { - // TODO: reset colours in text boxes (workaround is to resave the font) - // TODO: reset colours in context menus (seems to only affect the context menu on the username in chat) + try{ for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { // System.out.println(info.getName()); diff --git a/src/urChatBasic/frontend/dialogs/MessageDialog.java b/src/urChatBasic/frontend/dialogs/MessageDialog.java index ec1b790..fb89056 100644 --- a/src/urChatBasic/frontend/dialogs/MessageDialog.java +++ b/src/urChatBasic/frontend/dialogs/MessageDialog.java @@ -2,6 +2,8 @@ import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.util.function.Consumer; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; @@ -16,6 +18,19 @@ public class MessageDialog extends DialogBase { public MessageDialog (String message, String title, int messageType) { super(DriverGUI.frame, title, true); + setupDialog(message, title, messageType); + setActionListener(closeButton, null); + } + + public MessageDialog (String message, String title, int messageType, Consumer actionFunction) + { + super(DriverGUI.frame, title, true); + setupDialog(message, title, messageType); + setActionListener(closeButton, actionFunction); + } + + public void setupDialog(String message, String title, int messageType) + { setSize(300, 150); setResizable(false); setMaximumSize(new Dimension(300, 150)); @@ -27,9 +42,7 @@ public MessageDialog (String message, String title, int messageType) messageLabel.setHorizontalAlignment(SwingConstants.LEFT); messageLabel.setVerticalAlignment(SwingConstants.TOP); // Top alignment for wrapping text - closeButton = new JButton("Close"); - closeButton.addActionListener(e -> dispose()); // Close the dialog dialogPanel = new JPanel(new BorderLayout()); dialogPanel.add(messageLabel, BorderLayout.CENTER); @@ -37,4 +50,19 @@ public MessageDialog (String message, String title, int messageType) add(dialogPanel); } + + private void setActionListener(JButton targetButton, Consumer actionFunction ) + { + targetButton.addActionListener(e -> { + if (actionFunction != null) { + actionFunction.accept(e); + } + dispose(); + }); + } + + public JButton getCloseButton() + { + return closeButton; + } } diff --git a/src/urChatBasic/frontend/dialogs/YesNoDialog.java b/src/urChatBasic/frontend/dialogs/YesNoDialog.java new file mode 100644 index 0000000..fb1a55c --- /dev/null +++ b/src/urChatBasic/frontend/dialogs/YesNoDialog.java @@ -0,0 +1,75 @@ +package urChatBasic.frontend.dialogs; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.util.function.Consumer; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import urChatBasic.base.DialogBase; +import urChatBasic.frontend.DriverGUI; + +public class YesNoDialog extends DialogBase { + private JLabel messageLabel; + private JButton yesButton; + private JButton noButton; + + public YesNoDialog (String message, String title, int messageType, Consumer returnFunction) + { + super(DriverGUI.frame, title, true); + setSize(300, 150); + setResizable(false); + setMaximumSize(new Dimension(300, 150)); + setLocationRelativeTo(DriverGUI.frame); + + messageLabel = new JLabel("" + message + ""); + messageLabel.setIcon(DialogBase.getIconForMessageType(messageType)); + messageLabel.setIconTextGap(15); + messageLabel.setHorizontalAlignment(SwingConstants.LEFT); + messageLabel.setVerticalAlignment(SwingConstants.TOP); // Top alignment for wrapping text + + + yesButton = new JButton("Yes"); + noButton = new JButton("No"); + + yesButton.addActionListener(e -> { + if (returnFunction != null) { + returnFunction.accept(e); + } + dispose(); + }); + + noButton.addActionListener(e -> { + if (returnFunction != null) { + returnFunction.accept(e); + } + dispose(); + }); + + dialogPanel = new JPanel(new BorderLayout()); + dialogPanel.add(messageLabel, BorderLayout.CENTER); + + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING)); + buttonPanel.add(noButton); + buttonPanel.add(yesButton); + + dialogPanel.add(buttonPanel, BorderLayout.SOUTH); + + + + add(dialogPanel); + } + + public JButton getNoButton() + { + return noButton; + } + + public JButton getYesButton() + { + return yesButton; + } +} diff --git a/src/urChatBasic/tests/backend/DialogTests.java b/src/urChatBasic/tests/backend/DialogTests.java new file mode 100644 index 0000000..c614a68 --- /dev/null +++ b/src/urChatBasic/tests/backend/DialogTests.java @@ -0,0 +1,97 @@ +package urChatBasic.tests.backend; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import urChatBasic.base.DialogBase; +import urChatBasic.frontend.dialogs.MessageDialog; +import urChatBasic.frontend.dialogs.YesNoDialog; +import static org.junit.Assert.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.prefs.BackingStoreException; +import javax.swing.JButton; +import javax.swing.JOptionPane; + +public class DialogTests +{ + protected boolean automateTests = false; + + protected void utilFunction() + { + // to test calling another function + } + + @Test + public void testMessageDialog() + { + // effectively final + AtomicBoolean passedTest = new AtomicBoolean(false); + + MessageDialog testDialog = + new MessageDialog("Test dialog message here", "Test dialog title", JOptionPane.ERROR_MESSAGE, + e -> { + passedTest.set(true); + }); + + if (automateTests) + { + JButton closeButton = testDialog.getCloseButton(); + closeButton.doClick(); + } else + { + testDialog.setVisible(true); + } + + + assertTrue("Didn't press the cancel button", passedTest.get()); + } + + @Test + public void testYesNoDialogWithBoolean() + { + AtomicBoolean cancelClicked = new AtomicBoolean(false); + + // Create an instance of ChoiceDialog with an anonymous function for cancel action + YesNoDialog testDialog = new YesNoDialog("Click 'No' in this dialog", "Test dialog title", + JOptionPane.QUESTION_MESSAGE, e -> cancelClicked.set(e.getActionCommand().equalsIgnoreCase("No"))); + + if (automateTests) + { + // Simulate clicking the No button + JButton noButton = testDialog.getNoButton(); + noButton.doClick(); + } else + { + testDialog.setVisible(true); + } + + // Assert that the cancel action was executed + assertTrue("No button wasn't pressed.", cancelClicked.get()); + } + + @Test + public void testYesNoDialogWithActionListener() + { + // effectively final + AtomicBoolean passedTest = new AtomicBoolean(false); + + // Create an instance of ChoiceDialog with an anonymous function for cancel action + YesNoDialog testDialog = new YesNoDialog("Click any button to execute the function", "Test dialog title", + JOptionPane.QUESTION_MESSAGE, e -> { + passedTest.set(true); + assertTrue(passedTest.get()); + }); + + if (automateTests) + { + // Simulate clicking the cancel button + JButton cancelButton = testDialog.getNoButton(); + cancelButton.doClick(); + } else + { + testDialog.setVisible(true); + } + + assertTrue("Failed because Yes or No wasn't pressed", passedTest.get()); + } +} From c4d3744dc1997ac0b8a588a1ddc875a11b4f334f Mon Sep 17 00:00:00 2001 From: matty-r Date: Sun, 24 Sep 2023 07:56:05 +1000 Subject: [PATCH 02/78] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f36efe2..32fa84f 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ urChat is a Java based IRC Client designed around simplicity and minimal resourc Contributions ====== +**Currently targeting ![Milestone v0.4.0](https://github.com/matty-r/urChat/tree/milestone-v0.4.0)** + If you would like to assist in the development of urChat take a look at the Issues associated with the project. Please let me know if you wish to tackle a certain issue. Usage From 8fbe1e785b2f5ca1ae7aef54a30d7a17a06789cc Mon Sep 17 00:00:00 2001 From: matty-r Date: Sun, 24 Sep 2023 10:24:10 +1000 Subject: [PATCH 03/78] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 32fa84f..db5abb9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ urChat is a Java based IRC Client designed around simplicity and minimal resourc Contributions ====== -**Currently targeting ![Milestone v0.4.0](https://github.com/matty-r/urChat/tree/milestone-v0.4.0)** +**Currently targeting ![Milestone v0.4.0](https://github.com/matty-r/urChat/milestone/3)** If you would like to assist in the development of urChat take a look at the Issues associated with the project. Please let me know if you wish to tackle a certain issue. From 8e1bb40891cc432ceb31fc939d764eb2b2037936 Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 3 Oct 2023 05:29:29 +1000 Subject: [PATCH 04/78] Add a line limit test, and some refactoring --- src/urChatBasic/base/IRCRoomBase.java | 131 ++++++++++-------- .../tests/backend/MessageHandlerTests.java | 57 ++++---- 2 files changed, 103 insertions(+), 85 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index a42a7bc..14e50cc 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -22,6 +22,8 @@ import java.util.prefs.Preferences; import javax.swing.*; import javax.swing.Timer; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import javax.swing.event.MouseInputAdapter; import javax.swing.text.*; @@ -87,7 +89,8 @@ public class IRCRoomBase extends JPanel // Users list area - // TODO: Users should be created per Server, and instead have a property to hold what channels they're in + // TODO: Users should be created per Server, and instead have a property to hold what channels + // they're in private List usersArray = new ArrayList(); private UsersListModel usersListModel = new UsersListModel(usersArray); @SuppressWarnings("unchecked") @@ -161,13 +164,14 @@ public void setServer(IRCServerBase server) private void initRoom() { - if(null != getServer()) + if (null != getServer()) { roomPrefs = gui.getFavouritesPath().node(getServer().getName()).node(roomName); fontDialog = new FontDialog(roomName, gui.getFont(), roomPrefs); lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer().getNick()); - } else { + } else + { roomPrefs = gui.getFavouritesPath().node(roomName); fontDialog = new FontDialog(roomName, gui.getFont(), roomPrefs); @@ -206,13 +210,13 @@ private void setupMainPanel() setupUsersList(); // mainPanel.add(userScroller, BorderLayout.LINE_END); - //Create a split pane with the two scroll panes in it. - mainResizer = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, - channelScroll, userScroller); + // Create a split pane with the two scroll panes in it. + mainResizer = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, channelScroll, userScroller); mainResizer.setOneTouchExpandable(true); // This should be set to where the minimum size of the userScroller would end up - mainResizer.setDividerLocation(gui.getWidth() - (userScroller.getPreferredSize().width + mainResizer.getDividerSize())); + mainResizer.setDividerLocation( + gui.getWidth() - (userScroller.getPreferredSize().width + mainResizer.getDividerSize())); // Left most panel (channelScroll pane), gets the extra space when resizing the window mainResizer.setResizeWeight(1); @@ -232,11 +236,14 @@ public FontPanel getFontPanel() private void setupMainTextArea() { - channelScroll.setPreferredSize(new Dimension(Constants.MAIN_WIDTH - usersListWidth, Constants.MAIN_HEIGHT - BOTTOM_HEIGHT)); + channelScroll.setPreferredSize( + new Dimension(Constants.MAIN_WIDTH - usersListWidth, Constants.MAIN_HEIGHT - BOTTOM_HEIGHT)); channelScroll.setLocation(0, 0); channelScroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); channelTextArea.addMouseListener(new ChannelClickListener()); channelTextArea.addMouseMotionListener(new ChannelMovementListener()); + // channelTextArea.getDocument().addDocumentListener(new LimitLinesDocumentListener(gui.getLimitChannelLinesCount())); + // channelTextArea.getDocument().addDocumentListener(new LineLimitListener()); channelTextArea.setEditable(false); channelTextArea.setFont(getFontPanel().getFont()); channelTextArea.setEditorKit(new StyledEditorKit()); @@ -305,7 +312,7 @@ public void mouseClicked(MouseEvent e) Element ele = doc.getCharacterElement(channelTextArea.viewToModel2D((e.getPoint()))); AttributeSet as = ele.getAttributes(); ClickableText isClickableText = (ClickableText) as.getAttribute("clickableText"); - if(isClickableText != null) + if (isClickableText != null) { if (SwingUtilities.isRightMouseButton(e) && isClickableText.rightClickMenu() != null) { @@ -320,7 +327,8 @@ public void mouseClicked(MouseEvent e) class ChannelMovementListener extends MouseAdapter { - public void mouseMoved(MouseEvent e) { + public void mouseMoved(MouseEvent e) + { StyledDocument doc = (StyledDocument) channelTextArea.getDocument(); Element wordElement = doc.getCharacterElement(channelTextArea.viewToModel2D((e.getPoint()))); AttributeSet wordAttributeSet = wordElement.getAttributes(); @@ -328,7 +336,8 @@ public void mouseMoved(MouseEvent e) { if (isClickableText != null && gui.isClickableLinksEnabled()) { channelTextArea.setCursor(new Cursor(Cursor.HAND_CURSOR)); - } else { + } else + { channelTextArea.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } } @@ -385,7 +394,7 @@ public void callForAttention() // TODO: Change this to accept IRCUser instead public void printText(String line, String fromUser) { - if(null == channelTextArea) + if (null == channelTextArea) { System.out.println("Cant print, shutting down"); return; @@ -435,7 +444,7 @@ public void printText(String line, String fromUser) } // Always alert on IRCPrivate messages - if(this instanceof IRCPrivate) + if (this instanceof IRCPrivate) { callForAttention(); } @@ -457,8 +466,9 @@ public void toggleUsersList(Boolean showIt) if (usersListShown == showIt || usersListShown == null) { // userScroller.setVisible(showIt); - if(showIt) - mainResizer.setDividerLocation(gui.getWidth() - (userScroller.getPreferredSize().width + mainResizer.getDividerSize())); + if (showIt) + mainResizer.setDividerLocation( + gui.getWidth() - (userScroller.getPreferredSize().width + mainResizer.getDividerSize())); else mainResizer.setDividerLocation(gui.getWidth()); } @@ -499,21 +509,6 @@ public IRCUser getCreatedUsers(String userName) return null; } - public void doLimitLines() - { - if (gui.isLimitedChannelActivity()) - { - String[] tempText = channelTextArea.getText().split("\n"); - int linesCount = tempText.length; - - if (linesCount >= gui.getLimitChannelLinesCount()) - { - String newText = channelTextArea.getText().replace(tempText[0] + "\n", ""); - channelTextArea.setText(newText); - } - } - } - public void disableFocus() { channelTextArea.setFocusable(false); @@ -588,13 +583,14 @@ public void run() int index = 0; - while(index < usersArray.size()) + while (index < usersArray.size()) { if (usersArray.get(index).getName().matches(thisUser)) { usersArray.remove(index); createEvent("-- " + thisUser + " has quit " + channel); - } else { + } else + { index++; } } @@ -626,7 +622,7 @@ public void writeHistoryFile(String line) throws IOException { if (gui.saveChannelHistory()) { - if(historyFileName == null || historyFileName.isEmpty()) + if (historyFileName == null || historyFileName.isEmpty()) { historyFileName = historyDateFormat.format(todayDate) + " " + getName() + ".log"; } @@ -677,7 +673,8 @@ public View create(Element elem) { String kind = elem.getName(); - return switch (kind) { + return switch (kind) + { case AbstractDocument.ContentElementName -> new WrapLabelView(elem); case AbstractDocument.ParagraphElementName -> new ParagraphView(elem); case AbstractDocument.SectionElementName -> new BoxView(elem, View.Y_AXIS); @@ -697,7 +694,8 @@ public WrapLabelView(Element elem) public float getMinimumSpan(int axis) { - return switch (axis) { + return switch (axis) + { case View.X_AXIS -> 0; case View.Y_AXIS -> super.getMinimumSpan(axis); default -> throw new IllegalArgumentException("Invalid axis: " + axis); @@ -767,7 +765,7 @@ private class AddAsFavourite implements ActionListener @Override public void actionPerformed(ActionEvent arg0) { - if(null != getServer()) + if (null != getServer()) { if (!gui.isFavourite(IRCRoomBase.this)) { @@ -785,7 +783,7 @@ private class QuitItem implements ActionListener @Override public void actionPerformed(ActionEvent arg0) { - if(null != getServer()) + if (null != getServer()) { getServer().sendClientText("/part i'm outta here", getName()); } @@ -820,10 +818,12 @@ private class ToggleHideUsersListItem implements ActionListener public void actionPerformed(ActionEvent arg0) { - if(mainResizer.getDividerLocation() <= gui.getWidth() - (userScroller.getPreferredSize().width + mainResizer.getDividerSize()) ) + if (mainResizer.getDividerLocation() <= gui.getWidth() + - (userScroller.getPreferredSize().width + mainResizer.getDividerSize())) { usersListShown = false; - } else { + } else + { usersListShown = true; } toggleUsersList(usersListShown); @@ -845,13 +845,13 @@ private class SendTextListener implements ActionListener @Override public void actionPerformed(ActionEvent arg0) { - if (!getUserTextBox().getText().trim().isEmpty()) - { - sendClientText(clientTextBox.getText(), getName()); - if (gui.isClientHistoryEnabled()) - userHistory.add(clientTextBox.getText()); - } - clientTextBox.setText(""); + if (!getUserTextBox().getText().trim().isEmpty()) + { + sendClientText(clientTextBox.getText(), getName()); + if (gui.isClientHistoryEnabled()) + userHistory.add(clientTextBox.getText()); + } + clientTextBox.setText(""); } } @@ -885,7 +885,8 @@ public void run() { fontDialog.getFontPanel().setDefaultFont(f); - lineFormatter.setFont((StyledDocument) channelTextArea.getDocument(),fontDialog.getFontPanel().getFont()); + lineFormatter.setFont((StyledDocument) channelTextArea.getDocument(), + fontDialog.getFontPanel().getFont()); } }); } else @@ -905,7 +906,7 @@ public void actionPerformed(ActionEvent arg0) } } - public void quitRoom () + public void quitRoom() { eventTickerTimer.stop(); tickerPanel.setVisible(false); @@ -915,7 +916,7 @@ public void quitRoom () repaint(); } - public boolean userIsTyping () + public boolean userIsTyping() { return !clientTextBox.getText().isEmpty(); } @@ -1017,9 +1018,12 @@ public void keyPressed(KeyEvent e) } else { int nextTextInt = 0; - switch (e.getKeyCode()) { - case KeyEvent.VK_UP -> { - if (!userHistory.isEmpty()) { + switch (e.getKeyCode()) + { + case KeyEvent.VK_UP -> + { + if (!userHistory.isEmpty()) + { nextTextInt = userHistory.indexOf(clientTextBox.getText()) - 1; if (nextTextInt < 0) nextTextInt = userHistory.size() - 1; @@ -1027,8 +1031,10 @@ public void keyPressed(KeyEvent e) clientTextBox.setText(userHistory.get(nextTextInt)); } } - case KeyEvent.VK_DOWN -> { - if (!userHistory.isEmpty()) { + case KeyEvent.VK_DOWN -> + { + if (!userHistory.isEmpty()) + { nextTextInt = userHistory.indexOf(clientTextBox.getText()) + 1; if (nextTextInt > userHistory.size() - 1) nextTextInt = 0; @@ -1037,7 +1043,8 @@ public void keyPressed(KeyEvent e) } } case KeyEvent.VK_ESCAPE -> clientTextBox.setText(""); - default -> { + default -> + { if (lastUserToComplete != null) lastUserToComplete = null; if (startingCharacters != null) @@ -1068,10 +1075,12 @@ public void run() if (IRCRoomBase.this.tickerPanel.isVisible()) { Iterator labelIterator = eventLabels.iterator(); - while (labelIterator.hasNext()) { + while (labelIterator.hasNext()) + { JLabel tempLabel = labelIterator.next(); tempLabel.setLocation(tempLabel.getX() - EVENT_VELOCITY, 0); - if (tempLabel.getX() + tempLabel.getWidth() < 0) { + if (tempLabel.getX() + tempLabel.getWidth() < 0) + { labelIterator.remove(); // Safely remove the element tickerPanel.remove(tempLabel); } @@ -1080,7 +1089,7 @@ public void run() if (eventLabels.isEmpty()) eventTickerTimer.stop(); - if(DriverGUI.frame.isFocused()) + if (DriverGUI.frame.isFocused()) { tickerPanel.revalidate(); tickerPanel.repaint(); @@ -1089,7 +1098,8 @@ public void run() { eventTickerTimer.stop(); - for (JLabel tempLabel : eventLabels) { + for (JLabel tempLabel : eventLabels) + { tickerPanel.remove(tempLabel); } @@ -1123,7 +1133,8 @@ class UsersMouseListener extends MouseInputAdapter { public void mouseClicked(MouseEvent e) { - if (SwingUtilities.isRightMouseButton(e)){ + if (SwingUtilities.isRightMouseButton(e)) + { final int index = usersList.locationToIndex(e.getPoint()); if (index > -1) { diff --git a/src/urChatBasic/tests/backend/MessageHandlerTests.java b/src/urChatBasic/tests/backend/MessageHandlerTests.java index 17618f0..261ab61 100644 --- a/src/urChatBasic/tests/backend/MessageHandlerTests.java +++ b/src/urChatBasic/tests/backend/MessageHandlerTests.java @@ -11,6 +11,8 @@ import urChatBasic.frontend.IRCUser; import urChatBasic.frontend.UserGUI; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; import java.io.IOException; import javax.swing.text.BadLocationException; import javax.swing.text.StyledDocument; @@ -23,31 +25,6 @@ public class MessageHandlerTests { IRCUser testUser; Connection testConnection; - // helper functions - private String getLatestLine(StyledDocument doc) - { - int length = doc.getLength(); - - if (length == 0) { - return ""; // Return an empty string if the document is empty - } - - try { - int start = doc.getText(0, length).trim().lastIndexOf('\n') + 1; - int end = length; - - if (end == -1) { - end = length; - } - - return doc.getText(start, end - start).trim(); - } catch (BadLocationException e) { - e.printStackTrace(); - return ""; - } - } - - @Before public void setUp() throws Exception { DriverGUI.createGUI(); @@ -194,6 +171,36 @@ public void testQuitServer() assertEquals(MessageHandler.DisconnectMessage.class, testMessage.getMessageBase().getClass()); } + @Test + public void testLineLimit() throws BadLocationException + { + int channelLinesLimit = testGUI.getLimitChannelLinesCount(); + int serverLinesLimit = testGUI.getLimitServerLinesCount(); + + String channelMessage = ":"+testUser+"!~"+testUser+"@urchatclient PRIVMSG #somechannel :line # "; + String serverMessage = ":"+testServer.getName()+" 001 "+testUser+" :line # "; + + for (int i = 0; i < channelLinesLimit+10; i++) { + Message testMessage = testHandler.new Message(channelMessage + i); + testHandler.parseMessage(testMessage); + } + + for (int i = 0; i < serverLinesLimit+10; i++) { + Message testMessage = testHandler.new Message(serverMessage + i); + testHandler.parseMessage(testMessage); + } + + int serverLinesCount = testServer.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); + int channelLinesCount = testChannel.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); + + StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); + String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // " line # 509" + + assertTrue("Last line should line # 509", testLine.endsWith(" line # 509")); + assertTrue("First line should be line # 9", testServer.getChannelTextPane().getText().split("\n")[0].endsWith(" line # 10")); + assertSame("Channel line count should equal the line limit", channelLinesLimit, channelLinesCount); + } + @Test public void emojiMessage() { From 166050831fee71d37a9a0f9e8347f846ea605f23 Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 3 Oct 2023 06:47:37 +1000 Subject: [PATCH 05/78] Implemented a message queue to work with the line limits. Test is passing. --- src/urChatBasic/base/IRCRoomBase.java | 171 +++++++++++++----- src/urChatBasic/frontend/UserGUI.java | 6 + .../tests/backend/MessageHandlerTests.java | 29 ++- 3 files changed, 146 insertions(+), 60 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 14e50cc..88c0862 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -18,12 +18,12 @@ import java.text.*; import java.util.*; import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import java.util.logging.Level; import java.util.prefs.Preferences; import javax.swing.*; import javax.swing.Timer; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; import javax.swing.event.MouseInputAdapter; import javax.swing.text.*; @@ -85,6 +85,7 @@ public class IRCRoomBase extends JPanel // Room Text Area private JTextPane channelTextArea = new JTextPane(); private JScrollPane channelScroll = new JScrollPane(channelTextArea); + private BlockingQueue channelMessageQueue = new ArrayBlockingQueue<>(20); private LineFormatter lineFormatter; @@ -247,6 +248,7 @@ private void setupMainTextArea() channelTextArea.setEditable(false); channelTextArea.setFont(getFontPanel().getFont()); channelTextArea.setEditorKit(new StyledEditorKit()); + handleMessageQueue(); } private void setupUsersList() @@ -391,68 +393,137 @@ public void callForAttention() myActions.callForAttention(); } - // TODO: Change this to accept IRCUser instead - public void printText(String line, String fromUser) - { - if (null == channelTextArea) - { - System.out.println("Cant print, shutting down"); - return; + class MessagePair { + private String line; + private String fromUser; + + public MessagePair(String line, String fromUser) { + this.line = line; + this.fromUser = fromUser; } - DateFormat chatDateFormat = new SimpleDateFormat("HHmm"); - Date chatDate = new Date(); - String timeLine = ""; + public String getLine() { + return line; + } - if (gui.isTimeStampsEnabled()) - timeLine = "[" + chatDateFormat.format(chatDate) + "]"; + public String getUser() { + return fromUser; + } + } - if (gui.isChannelHistoryEnabled()) - { - try - { - writeHistoryFile(line); - } catch (IOException e) - { - Constants.LOGGER.log(Level.WARNING, e.getLocalizedMessage()); - } + public void printText(String line, String fromUser) { + try { + channelMessageQueue.put(new MessagePair(line, fromUser)); + } catch (InterruptedException e) { + e.printStackTrace(); } + } - StyledDocument doc = (StyledDocument) channelTextArea.getDocument(); - IRCUser fromIRCUser = getCreatedUsers(fromUser); + public boolean channelQueueEmpty() + { + return channelMessageQueue.isEmpty(); + } - // If we received a message from a user that isn't in the channel - // then add them to the users list. - // But don't add them if it's from the Event Ticker - if (fromIRCUser == null) - { - if (!fromUser.equals(Constants.EVENT_USER)) + // TODO: Change this to accept IRCUser instead + public void handleMessageQueue() + { + new Thread(() -> { + while (true) { - addToUsersList(getName(), fromUser); - fromIRCUser = getCreatedUsers(fromUser); - } - } + try + { + MessagePair messagePair = channelMessageQueue.take(); + Document document = channelTextArea.getDocument(); + Element root = document.getDefaultRootElement(); - if (fromUser.equals(Constants.EVENT_USER) || !fromIRCUser.isMuted()) - { - lineFormatter.formattedDocument(doc, timeLine, fromIRCUser, fromUser, line); - if (lineFormatter.nameStyle.getAttribute("name") == lineFormatter.highStyle().getAttribute("name")) - { - callForAttention(); - } + while (root.getElementCount() > gui.getLimitChannelLinesCount()) + { + Element line = root.getElement(0); + int end = line.getEndOffset(); - // Always alert on IRCPrivate messages - if (this instanceof IRCPrivate) - { - callForAttention(); + try + { + document.remove(0, end); + } + catch(BadLocationException ble) + { + System.out.println(ble); + } + } + + String line = messagePair.getLine(); + String fromUser = messagePair.getUser(); + + if (null == channelTextArea) + { + System.out.println("Cant print, shutting down"); + return; + } + + DateFormat chatDateFormat = new SimpleDateFormat("HHmm"); + Date chatDate = new Date(); + String timeLine = ""; + + if (gui.isTimeStampsEnabled()) + timeLine = "[" + chatDateFormat.format(chatDate) + "]"; + + if (gui.isChannelHistoryEnabled()) + { + try + { + writeHistoryFile(line); + } catch (IOException e) + { + Constants.LOGGER.log(Level.WARNING, e.getLocalizedMessage()); + } + } + + StyledDocument doc = (StyledDocument) channelTextArea.getDocument(); + IRCUser fromIRCUser = getCreatedUsers(fromUser); + + // If we received a message from a user that isn't in the channel + // then add them to the users list. + // But don't add them if it's from the Event Ticker + if (fromIRCUser == null) + { + if (!fromUser.equals(Constants.EVENT_USER)) + { + addToUsersList(getName(), fromUser); + fromIRCUser = getCreatedUsers(fromUser); + } + } + + + if (fromUser.equals(Constants.EVENT_USER) || !fromIRCUser.isMuted()) + { + lineFormatter.formattedDocument(doc, timeLine, fromIRCUser, fromUser, line); + + if (lineFormatter.nameStyle.getAttribute("name") == lineFormatter.highStyle() + .getAttribute("name")) + { + callForAttention(); + } + + // Always alert on IRCPrivate messages + if (this instanceof IRCPrivate) + { + callForAttention(); + } + + // TODO: Scrolls to the bottom of the channelTextArea on message received, this should be + // disabled + // when the user has scrolled up + channelTextArea.setCaretPosition(channelTextArea.getDocument().getLength()); + } + } catch (InterruptedException e) + { + e.printStackTrace(); + } } + }).start(); - // TODO: Scrolls to the bottom of the channelTextArea on message received, this should be disabled - // when the user has scrolled up - channelTextArea.setCaretPosition(channelTextArea.getDocument().getLength()); - } } /** diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index d26748c..230cc52 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -143,6 +143,12 @@ public int getLimitServerLinesCount() } } + public void setLimitChanneLines(int limit) + { + limitChannelLinesCount.setText(Integer.toString(limit)); + + } + /* * (non-Javadoc) * diff --git a/src/urChatBasic/tests/backend/MessageHandlerTests.java b/src/urChatBasic/tests/backend/MessageHandlerTests.java index 261ab61..7683092 100644 --- a/src/urChatBasic/tests/backend/MessageHandlerTests.java +++ b/src/urChatBasic/tests/backend/MessageHandlerTests.java @@ -14,6 +14,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.concurrent.TimeUnit; import javax.swing.text.BadLocationException; import javax.swing.text.StyledDocument; @@ -172,33 +173,41 @@ public void testQuitServer() } @Test - public void testLineLimit() throws BadLocationException + public void testLineLimit() throws BadLocationException, InterruptedException { + testGUI.setLimitChanneLines(10); int channelLinesLimit = testGUI.getLimitChannelLinesCount(); - int serverLinesLimit = testGUI.getLimitServerLinesCount(); + // int serverLinesLimit = testGUI.getLimitServerLinesCount(); String channelMessage = ":"+testUser+"!~"+testUser+"@urchatclient PRIVMSG #somechannel :line # "; - String serverMessage = ":"+testServer.getName()+" 001 "+testUser+" :line # "; + // String serverMessage = ":"+testServer.getName()+" 001 "+testUser+" :line # "; for (int i = 0; i < channelLinesLimit+10; i++) { Message testMessage = testHandler.new Message(channelMessage + i); testHandler.parseMessage(testMessage); } - for (int i = 0; i < serverLinesLimit+10; i++) { - Message testMessage = testHandler.new Message(serverMessage + i); - testHandler.parseMessage(testMessage); + while(!testChannel.channelQueueEmpty()) + { + TimeUnit.SECONDS.sleep(1); } - int serverLinesCount = testServer.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); + // for (int i = 0; i < serverLinesLimit+10; i++) { + // Message testMessage = testHandler.new Message(serverMessage + i); + // testHandler.parseMessage(testMessage); + // } + + // int serverLinesCount = testServer.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); int channelLinesCount = testChannel.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // " line # 509" - assertTrue("Last line should line # 509", testLine.endsWith(" line # 509")); - assertTrue("First line should be line # 9", testServer.getChannelTextPane().getText().split("\n")[0].endsWith(" line # 10")); - assertSame("Channel line count should equal the line limit", channelLinesLimit, channelLinesCount); + assertTrue("Last line should line # 19", testLine.endsWith(" line # 19")); + + System.out.println(); + assertTrue("First line should be line # 11 but it was "+testChannel.getChannelTextPane().getText().split("\n")[0], testChannel.getChannelTextPane().getText().split("\n")[0].endsWith(" line # 11")); + assertSame("Channel line count should equal the line limit", channelLinesLimit, channelLinesCount - 1); } @Test From c1448f7df6e64e92a0e6b538f91421966404b8c4 Mon Sep 17 00:00:00 2001 From: matty_r Date: Fri, 6 Oct 2023 06:20:50 +1000 Subject: [PATCH 06/78] Refactoring to remove unused imports, adjust the function to determine if the message queue is working - for use with tests where it requires a specific order --- src/urChatBasic/base/IRCRoomBase.java | 40 +++++++++++-------- src/urChatBasic/base/UserGUIBase.java | 1 - .../base/capabilities/CapTypeBase.java | 2 - src/urChatBasic/frontend/IRCActions.java | 1 - src/urChatBasic/frontend/IRCServer.java | 1 - src/urChatBasic/frontend/UserGUI.java | 8 +++- .../frontend/components/DnDTabbedPane.java | 4 +- .../tests/backend/DialogTests.java | 4 -- .../tests/backend/MessageHandlerTests.java | 22 +++++++--- 9 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 88c0862..10a55e8 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -86,6 +86,7 @@ public class IRCRoomBase extends JPanel private JTextPane channelTextArea = new JTextPane(); private JScrollPane channelScroll = new JScrollPane(channelTextArea); private BlockingQueue channelMessageQueue = new ArrayBlockingQueue<>(20); + public boolean channelQueueInProgress = false; private LineFormatter lineFormatter; @@ -347,6 +348,9 @@ public void mouseMoved(MouseEvent e) public void createEvent(String eventText) { + if (gui.isJoinsQuitsMainEnabled()) + printText(eventText, Constants.EVENT_USER); + eventTickerTimer.setDelay(gui.getEventTickerDelay()); if (gui.isJoinsQuitsTickerEnabled()) { @@ -383,9 +387,6 @@ public void createEvent(String eventText) if (!(eventTickerTimer.isRunning())) eventTickerTimer.start(); } - - if (gui.isJoinsQuitsMainEnabled()) - printText(eventText, Constants.EVENT_USER); } public void callForAttention() @@ -411,6 +412,7 @@ public String getUser() { } } + // TODO: Change this to accept IRCUser instead public void printText(String line, String fromUser) { try { channelMessageQueue.put(new MessagePair(line, fromUser)); @@ -419,12 +421,11 @@ public void printText(String line, String fromUser) { } } - public boolean channelQueueEmpty() + public boolean channelQueueWorking() { - return channelMessageQueue.isEmpty(); + return (!channelMessageQueue.isEmpty() || channelQueueInProgress); } - // TODO: Change this to accept IRCUser instead public void handleMessageQueue() { new Thread(() -> { @@ -434,31 +435,35 @@ public void handleMessageQueue() { MessagePair messagePair = channelMessageQueue.take(); + if(null != messagePair) + { + channelQueueInProgress = true; + } + + String line = messagePair.getLine(); + String fromUser = messagePair.getUser(); + Document document = channelTextArea.getDocument(); Element root = document.getDefaultRootElement(); - - while (root.getElementCount() > gui.getLimitChannelLinesCount()) + if(null != messagePair && root.getElementCount() > gui.getLimitChannelLinesCount()) { - Element line = root.getElement(0); - int end = line.getEndOffset(); + Element firstLine = root.getElement(0); + int endIndex = firstLine.getEndOffset(); try { - document.remove(0, end); + document.remove(0, endIndex); } catch(BadLocationException ble) { - System.out.println(ble); + Constants.LOGGER.log(Level.WARNING, ble.getLocalizedMessage()); } } - String line = messagePair.getLine(); - String fromUser = messagePair.getUser(); - if (null == channelTextArea) { - System.out.println("Cant print, shutting down"); + Constants.LOGGER.log(Level.WARNING, "ChannelTextArea hasn't initialized or has disappeared.. not printing text."); return; } @@ -516,10 +521,11 @@ public void handleMessageQueue() // disabled // when the user has scrolled up channelTextArea.setCaretPosition(channelTextArea.getDocument().getLength()); + channelQueueInProgress = false; } } catch (InterruptedException e) { - e.printStackTrace(); + Constants.LOGGER.log(Level.WARNING, e.getLocalizedMessage()); } } }).start(); diff --git a/src/urChatBasic/base/UserGUIBase.java b/src/urChatBasic/base/UserGUIBase.java index a3cf359..33a7194 100644 --- a/src/urChatBasic/base/UserGUIBase.java +++ b/src/urChatBasic/base/UserGUIBase.java @@ -1,6 +1,5 @@ package urChatBasic.base; -import java.awt.Graphics; import java.util.prefs.Preferences; import urChatBasic.base.capabilities.CapTypeBase; diff --git a/src/urChatBasic/base/capabilities/CapTypeBase.java b/src/urChatBasic/base/capabilities/CapTypeBase.java index 8e9ed6b..078e2e6 100644 --- a/src/urChatBasic/base/capabilities/CapTypeBase.java +++ b/src/urChatBasic/base/capabilities/CapTypeBase.java @@ -1,7 +1,5 @@ package urChatBasic.base.capabilities; -import java.util.ArrayList; - public interface CapTypeBase { enum Category { AUTHENTICATION diff --git a/src/urChatBasic/frontend/IRCActions.java b/src/urChatBasic/frontend/IRCActions.java index 8bb33ce..237b075 100644 --- a/src/urChatBasic/frontend/IRCActions.java +++ b/src/urChatBasic/frontend/IRCActions.java @@ -4,7 +4,6 @@ import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import javax.swing.JPanel; import javax.swing.Timer; import urChatBasic.base.IRCActionsBase; import urChatBasic.base.IRCRoomBase; diff --git a/src/urChatBasic/frontend/IRCServer.java b/src/urChatBasic/frontend/IRCServer.java index be5d441..00aa43b 100644 --- a/src/urChatBasic/frontend/IRCServer.java +++ b/src/urChatBasic/frontend/IRCServer.java @@ -15,7 +15,6 @@ import java.util.Iterator; import java.util.List; import java.util.logging.Level; -import java.util.stream.IntStream; import javax.swing.ImageIcon; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 230cc52..f216152 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -146,7 +146,6 @@ public int getLimitServerLinesCount() public void setLimitChanneLines(int limit) { limitChannelLinesCount.setText(Integer.toString(limit)); - } /* @@ -374,6 +373,11 @@ public Boolean isJoinsQuitsMainEnabled() return showJoinsQuitsMainWindow.isSelected(); } + public void setJoinsQuitsMain(boolean enable) + { + showJoinsQuitsMainWindow.setSelected(enable); + } + /* * (non-Javadoc) * @@ -960,7 +964,7 @@ public void actionPerformed(ActionEvent arg0) if (tab instanceof IRCRoomBase) { IRCRoomBase tabRoom = (IRCRoomBase) tab; - if (tabRoom.getServer().equals(favServer) && tabRoom.getName().equals(favChannel)) + if (tabRoom.getServer().getName().equals(favServer) && tabRoom.getName().equals(favChannel)) { tabRoom.getFontPanel().setFont(favFontDialog.getFontPanel().getFont(), true); tabRoom.setFont(favFontDialog.getFontPanel().getFont()); diff --git a/src/urChatBasic/frontend/components/DnDTabbedPane.java b/src/urChatBasic/frontend/components/DnDTabbedPane.java index 02a64f7..6c458e8 100644 --- a/src/urChatBasic/frontend/components/DnDTabbedPane.java +++ b/src/urChatBasic/frontend/components/DnDTabbedPane.java @@ -18,7 +18,7 @@ public class DnDTabbedPane extends JTabbedPane { private static final int LINE_SIZE = 3; private static final int RWH = 20; - private static final int BUTTON_SIZE = 30; // XXX 30 is magic number of scroll button size + private static final int BUTTON_SIZE = 30; private final GhostGlassPane glassPane = new GhostGlassPane(this); protected int dragTabIndex = -1; @@ -221,7 +221,6 @@ protected void initGlassPane(Point tabPt) { protected Rectangle getTabAreaBounds() { Rectangle tabbedRect = getBounds(); - // XXX: Rectangle compRect = getSelectedComponent().getBounds(); // pointed out by daryl. NullPointerException: i.e. addTab("Tab", null) // Component comp = getSelectedComponent(); // int idx = 0; @@ -393,7 +392,6 @@ private static Optional getGhostGlassPane(Component c) { // Component c = e.getDropTargetContext().getComponent(); // System.out.println("DropTargetListener#dragExit: " + c.getName()); getGhostGlassPane(e.getDropTargetContext().getComponent()).ifPresent(glassPane -> { - // XXX: glassPane.setVisible(false); glassPane.setPoint(HIDDEN_POINT); glassPane.setTargetRect(0, 0, 0, 0); glassPane.repaint(); diff --git a/src/urChatBasic/tests/backend/DialogTests.java b/src/urChatBasic/tests/backend/DialogTests.java index c614a68..58e3d12 100644 --- a/src/urChatBasic/tests/backend/DialogTests.java +++ b/src/urChatBasic/tests/backend/DialogTests.java @@ -1,14 +1,10 @@ package urChatBasic.tests.backend; -import org.junit.After; -import org.junit.Before; import org.junit.Test; -import urChatBasic.base.DialogBase; import urChatBasic.frontend.dialogs.MessageDialog; import urChatBasic.frontend.dialogs.YesNoDialog; import static org.junit.Assert.*; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.prefs.BackingStoreException; import javax.swing.JButton; import javax.swing.JOptionPane; diff --git a/src/urChatBasic/tests/backend/MessageHandlerTests.java b/src/urChatBasic/tests/backend/MessageHandlerTests.java index 7683092..2354f1d 100644 --- a/src/urChatBasic/tests/backend/MessageHandlerTests.java +++ b/src/urChatBasic/tests/backend/MessageHandlerTests.java @@ -58,7 +58,7 @@ public void recvActionMessage() } @Test - public void nickIsHighStyleTest() throws BadLocationException + public void nickIsHighStyleTest() throws BadLocationException, InterruptedException { String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG testUser :hello testUser!"; Message testMessage = testHandler.new Message(rawMessage); @@ -66,12 +66,17 @@ public void nickIsHighStyleTest() throws BadLocationException StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] hello testUser!" + while(testChannel.channelQueueWorking()) + { + TimeUnit.SECONDS.sleep(1); + } + // Should be highStyle because someuser mentioned my nick, testUser assertEquals("highStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 11, testLine).getAttribute("name")); } @Test - public void nickIsDefaultStyleTest() throws BadLocationException + public void nickIsDefaultStyleTest() throws BadLocationException, InterruptedException { String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG #somechannel :Welcome to somechannel!"; Message testMessage = testHandler.new Message(rawMessage); @@ -79,6 +84,11 @@ public void nickIsDefaultStyleTest() throws BadLocationException StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] hello world!" + while(testChannel.channelQueueWorking()) + { + TimeUnit.SECONDS.sleep(1); + } + // Should be defaultStyle because the user didn't mention testUser and is just a normal message assertEquals("defaultStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 11, testLine).getAttribute("name")); } @@ -176,6 +186,7 @@ public void testQuitServer() public void testLineLimit() throws BadLocationException, InterruptedException { testGUI.setLimitChanneLines(10); + testGUI.setJoinsQuitsMain(false); int channelLinesLimit = testGUI.getLimitChannelLinesCount(); // int serverLinesLimit = testGUI.getLimitServerLinesCount(); @@ -187,7 +198,7 @@ public void testLineLimit() throws BadLocationException, InterruptedException testHandler.parseMessage(testMessage); } - while(!testChannel.channelQueueEmpty()) + while(testChannel.channelQueueWorking()) { TimeUnit.SECONDS.sleep(1); } @@ -203,10 +214,9 @@ public void testLineLimit() throws BadLocationException, InterruptedException StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // " line # 509" - assertTrue("Last line should line # 19", testLine.endsWith(" line # 19")); + assertTrue("Last line should line # 19 but it was"+testLine, testLine.endsWith(" line # 19")); - System.out.println(); - assertTrue("First line should be line # 11 but it was "+testChannel.getChannelTextPane().getText().split("\n")[0], testChannel.getChannelTextPane().getText().split("\n")[0].endsWith(" line # 11")); + assertTrue("First line should be line # 10 but it was "+testChannel.getChannelTextPane().getText().split("\n")[0], testChannel.getChannelTextPane().getText().split("\n")[0].endsWith(" line # 10")); assertSame("Channel line count should equal the line limit", channelLinesLimit, channelLinesCount - 1); } From 4ea5352ef7329c8f7db628cca5c53162f9cfe8b6 Mon Sep 17 00:00:00 2001 From: matty_r Date: Fri, 6 Oct 2023 06:49:08 +1000 Subject: [PATCH 07/78] Adds test for server line limits --- src/urChatBasic/base/IRCRoomBase.java | 29 ++++++++---- src/urChatBasic/frontend/UserGUI.java | 7 ++- .../tests/backend/MessageHandlerTests.java | 46 +++++++++++++++---- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 10a55e8..60150e9 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -4,6 +4,7 @@ import urChatBasic.frontend.DriverGUI; import urChatBasic.frontend.IRCActions; import urChatBasic.frontend.IRCPrivate; +import urChatBasic.frontend.IRCServer; import urChatBasic.frontend.IRCUser; import urChatBasic.frontend.LineFormatter; import urChatBasic.frontend.LineFormatter.ClickableText; @@ -82,11 +83,11 @@ public class IRCRoomBase extends JPanel private String lastUserToComplete = null; private List autoCompleteNames = new ArrayList(); - // Room Text Area + // Text Area private JTextPane channelTextArea = new JTextPane(); private JScrollPane channelScroll = new JScrollPane(channelTextArea); - private BlockingQueue channelMessageQueue = new ArrayBlockingQueue<>(20); - public boolean channelQueueInProgress = false; + private BlockingQueue messageQueue = new ArrayBlockingQueue<>(20); + public boolean messageQueueInProgress = false; private LineFormatter lineFormatter; @@ -415,15 +416,15 @@ public String getUser() { // TODO: Change this to accept IRCUser instead public void printText(String line, String fromUser) { try { - channelMessageQueue.put(new MessagePair(line, fromUser)); + messageQueue.put(new MessagePair(line, fromUser)); } catch (InterruptedException e) { e.printStackTrace(); } } - public boolean channelQueueWorking() + public boolean messageQueueWorking() { - return (!channelMessageQueue.isEmpty() || channelQueueInProgress); + return (!messageQueue.isEmpty() || messageQueueInProgress); } public void handleMessageQueue() @@ -433,11 +434,14 @@ public void handleMessageQueue() { try { - MessagePair messagePair = channelMessageQueue.take(); + MessagePair messagePair = messageQueue.take(); if(null != messagePair) { - channelQueueInProgress = true; + messageQueueInProgress = true; + } else + { + continue; } String line = messagePair.getLine(); @@ -446,7 +450,12 @@ public void handleMessageQueue() Document document = channelTextArea.getDocument(); Element root = document.getDefaultRootElement(); - if(null != messagePair && root.getElementCount() > gui.getLimitChannelLinesCount()) + int lineLimit = gui.getLimitChannelLinesCount(); + + if(this instanceof IRCServer) + lineLimit = gui.getLimitServerLinesCount(); + + if(null != messagePair && root.getElementCount() > lineLimit) { Element firstLine = root.getElement(0); int endIndex = firstLine.getEndOffset(); @@ -521,7 +530,7 @@ public void handleMessageQueue() // disabled // when the user has scrolled up channelTextArea.setCaretPosition(channelTextArea.getDocument().getLength()); - channelQueueInProgress = false; + messageQueueInProgress = false; } } catch (InterruptedException e) { diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index f216152..f6b952e 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -143,11 +143,16 @@ public int getLimitServerLinesCount() } } - public void setLimitChanneLines(int limit) + public void setLimitChannelLines(int limit) { limitChannelLinesCount.setText(Integer.toString(limit)); } + public void setLimitServerLines(int limit) + { + limitServerLinesCount.setText(Integer.toString(limit)); + } + /* * (non-Javadoc) * diff --git a/src/urChatBasic/tests/backend/MessageHandlerTests.java b/src/urChatBasic/tests/backend/MessageHandlerTests.java index 2354f1d..bba6a61 100644 --- a/src/urChatBasic/tests/backend/MessageHandlerTests.java +++ b/src/urChatBasic/tests/backend/MessageHandlerTests.java @@ -66,7 +66,7 @@ public void nickIsHighStyleTest() throws BadLocationException, InterruptedExcept StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] hello testUser!" - while(testChannel.channelQueueWorking()) + while(testChannel.messageQueueWorking()) { TimeUnit.SECONDS.sleep(1); } @@ -84,7 +84,7 @@ public void nickIsDefaultStyleTest() throws BadLocationException, InterruptedExc StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] hello world!" - while(testChannel.channelQueueWorking()) + while(testChannel.messageQueueWorking()) { TimeUnit.SECONDS.sleep(1); } @@ -183,22 +183,20 @@ public void testQuitServer() } @Test - public void testLineLimit() throws BadLocationException, InterruptedException + public void testChannelLineLimit() throws BadLocationException, InterruptedException { - testGUI.setLimitChanneLines(10); + testGUI.setLimitChannelLines(10); testGUI.setJoinsQuitsMain(false); int channelLinesLimit = testGUI.getLimitChannelLinesCount(); - // int serverLinesLimit = testGUI.getLimitServerLinesCount(); String channelMessage = ":"+testUser+"!~"+testUser+"@urchatclient PRIVMSG #somechannel :line # "; - // String serverMessage = ":"+testServer.getName()+" 001 "+testUser+" :line # "; for (int i = 0; i < channelLinesLimit+10; i++) { Message testMessage = testHandler.new Message(channelMessage + i); testHandler.parseMessage(testMessage); } - while(testChannel.channelQueueWorking()) + while(testChannel.messageQueueWorking()) { TimeUnit.SECONDS.sleep(1); } @@ -214,12 +212,42 @@ public void testLineLimit() throws BadLocationException, InterruptedException StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // " line # 509" - assertTrue("Last line should line # 19 but it was"+testLine, testLine.endsWith(" line # 19")); + assertTrue("Last line should line # 19 but it was"+testLine, testLine.endsWith("line # 19")); - assertTrue("First line should be line # 10 but it was "+testChannel.getChannelTextPane().getText().split("\n")[0], testChannel.getChannelTextPane().getText().split("\n")[0].endsWith(" line # 10")); + assertTrue("First line should be line # 10 but it was "+testChannel.getChannelTextPane().getText().split("\n")[0], testChannel.getChannelTextPane().getText().split("\n")[0].endsWith("line # 10")); assertSame("Channel line count should equal the line limit", channelLinesLimit, channelLinesCount - 1); } + @Test + public void testServerLineLimit() throws BadLocationException, InterruptedException + { + testGUI.setLimitServerLines(10); + testGUI.setJoinsQuitsMain(false); + int serverLinesLimit = testGUI.getLimitServerLinesCount(); + + String serverMessage = ":"+testServer.getName()+" 001 "+testUser+" :line # "; + + for (int i = 0; i < serverLinesLimit+10; i++) { + Message testMessage = testHandler.new Message(serverMessage + i); + testHandler.parseMessage(testMessage); + } + + while(testServer.messageQueueWorking()) + { + TimeUnit.SECONDS.sleep(1); + } + + int serverLinesCount = testServer.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); + + StyledDocument testDoc = testServer.getChannelTextPane().getStyledDocument(); + String testLine = testServer.getLineFormatter().getLatestLine(testDoc); // " line # 19" + + assertTrue("Last line should line # 19 but it was"+testLine, testLine.endsWith("line # 19")); + + assertTrue("First line should be line # 10 but it was "+testServer.getChannelTextPane().getText().split("\n")[0], testServer.getChannelTextPane().getText().split("\n")[0].endsWith("line # 10")); + assertSame("Channel line count should equal the line limit", serverLinesLimit, serverLinesCount - 1); + } + @Test public void emojiMessage() { From a99b0f4abedbc8b8a07dad96da3b18b1c791312f Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 7 Oct 2023 22:07:06 +1000 Subject: [PATCH 08/78] Switch to using the EDT for the handleMessageQueue --- src/urChatBasic/base/Constants.java | 2 +- src/urChatBasic/base/IRCRoomBase.java | 201 ++++++++++++++------------ 2 files changed, 110 insertions(+), 93 deletions(-) diff --git a/src/urChatBasic/base/Constants.java b/src/urChatBasic/base/Constants.java index f136dc4..bd93135 100644 --- a/src/urChatBasic/base/Constants.java +++ b/src/urChatBasic/base/Constants.java @@ -24,7 +24,7 @@ */ public class Constants { - public static String UR_VERSION = "v0.3.0"; + public static String UR_VERSION = "v0.4.0"; public static String URL_SEPARATOR = "/"; public static final URL RESOURCES_DIR = DriverGUI.class.getResource(URL_SEPARATOR + "images" + URL_SEPARATOR); public static final String THEMES_DIR = "themes" + URL_SEPARATOR; diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 60150e9..a21ab2d 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -250,7 +250,6 @@ private void setupMainTextArea() channelTextArea.setEditable(false); channelTextArea.setFont(getFontPanel().getFont()); channelTextArea.setEditorKit(new StyledEditorKit()); - handleMessageQueue(); } private void setupUsersList() @@ -417,6 +416,10 @@ public String getUser() { public void printText(String line, String fromUser) { try { messageQueue.put(new MessagePair(line, fromUser)); + + if(!messageQueueInProgress) + handleMessageQueue(); + } catch (InterruptedException e) { e.printStackTrace(); } @@ -429,115 +432,124 @@ public boolean messageQueueWorking() public void handleMessageQueue() { - new Thread(() -> { - while (true) + SwingUtilities.invokeLater(new Runnable() + { + public void run() { - try + while (!messageQueue.isEmpty()) { - MessagePair messagePair = messageQueue.take(); - - if(null != messagePair) - { - messageQueueInProgress = true; - } else + try { - continue; - } + MessagePair messagePair = messageQueue.take(); - String line = messagePair.getLine(); - String fromUser = messagePair.getUser(); + if(null != messagePair) + { + messageQueueInProgress = true; + } else + { + continue; + } - Document document = channelTextArea.getDocument(); - Element root = document.getDefaultRootElement(); + String line = messagePair.getLine(); + String fromUser = messagePair.getUser(); - int lineLimit = gui.getLimitChannelLinesCount(); + Document document = channelTextArea.getDocument(); + Element root = document.getDefaultRootElement(); - if(this instanceof IRCServer) - lineLimit = gui.getLimitServerLinesCount(); + int lineLimit = gui.getLimitChannelLinesCount(); - if(null != messagePair && root.getElementCount() > lineLimit) - { - Element firstLine = root.getElement(0); - int endIndex = firstLine.getEndOffset(); + if(IRCRoomBase.this instanceof IRCServer) + lineLimit = gui.getLimitServerLinesCount(); - try + if(null != messagePair && root.getElementCount() > lineLimit) { - document.remove(0, endIndex); + Element firstLine = root.getElement(0); + int endIndex = firstLine.getEndOffset(); + + try + { + document.remove(0, endIndex); + } + catch(BadLocationException ble) + { + Constants.LOGGER.log(Level.WARNING, ble.getLocalizedMessage()); + } } - catch(BadLocationException ble) + + if (null == channelTextArea) { - Constants.LOGGER.log(Level.WARNING, ble.getLocalizedMessage()); + Constants.LOGGER.log(Level.WARNING, "ChannelTextArea hasn't initialized or has disappeared.. not printing text."); + return; } - } - if (null == channelTextArea) - { - Constants.LOGGER.log(Level.WARNING, "ChannelTextArea hasn't initialized or has disappeared.. not printing text."); - return; - } + DateFormat chatDateFormat = new SimpleDateFormat("HHmm"); + Date chatDate = new Date(); + String timeLine = ""; - DateFormat chatDateFormat = new SimpleDateFormat("HHmm"); - Date chatDate = new Date(); - String timeLine = ""; + if (gui.isTimeStampsEnabled()) + timeLine = "[" + chatDateFormat.format(chatDate) + "]"; - if (gui.isTimeStampsEnabled()) - timeLine = "[" + chatDateFormat.format(chatDate) + "]"; - - if (gui.isChannelHistoryEnabled()) - { - try + if (gui.isChannelHistoryEnabled()) { - writeHistoryFile(line); - } catch (IOException e) - { - Constants.LOGGER.log(Level.WARNING, e.getLocalizedMessage()); + try + { + writeHistoryFile(line); + } catch (IOException e) + { + Constants.LOGGER.log(Level.WARNING, e.getLocalizedMessage()); + } } - } - StyledDocument doc = (StyledDocument) channelTextArea.getDocument(); - IRCUser fromIRCUser = getCreatedUsers(fromUser); + StyledDocument doc = (StyledDocument) channelTextArea.getDocument(); + IRCUser fromIRCUser = getCreatedUsers(fromUser); - // If we received a message from a user that isn't in the channel - // then add them to the users list. - // But don't add them if it's from the Event Ticker - if (fromIRCUser == null) - { - if (!fromUser.equals(Constants.EVENT_USER)) + // If we received a message from a user that isn't in the channel + // then add them to the users list. + // But don't add them if it's from the Event Ticker + if (fromIRCUser == null) { - addToUsersList(getName(), fromUser); - fromIRCUser = getCreatedUsers(fromUser); + if (!fromUser.equals(Constants.EVENT_USER)) + { + // TODO: Re-add later? + // addToUsersList(getName(), fromUser); + // fromIRCUser = getCreatedUsers(fromUser); + // System.out.println(); + Constants.LOGGER.log(Level.WARNING, "Message from a user that isn't in the user list!"); + fromIRCUser = new IRCUser(server, fromUser); + } } - } - - if (fromUser.equals(Constants.EVENT_USER) || !fromIRCUser.isMuted()) - { - lineFormatter.formattedDocument(doc, timeLine, fromIRCUser, fromUser, line); - if (lineFormatter.nameStyle.getAttribute("name") == lineFormatter.highStyle() - .getAttribute("name")) + if (fromUser.equals(Constants.EVENT_USER) || !fromIRCUser.isMuted()) { - callForAttention(); - } + lineFormatter.formattedDocument(doc, timeLine, fromIRCUser, fromUser, line); - // Always alert on IRCPrivate messages - if (this instanceof IRCPrivate) - { - callForAttention(); - } + if (lineFormatter.nameStyle.getAttribute("name") == lineFormatter.highStyle() + .getAttribute("name")) + { + callForAttention(); + } - // TODO: Scrolls to the bottom of the channelTextArea on message received, this should be - // disabled - // when the user has scrolled up - channelTextArea.setCaretPosition(channelTextArea.getDocument().getLength()); - messageQueueInProgress = false; + // Always alert on IRCPrivate messages + if (IRCRoomBase.this instanceof IRCPrivate) + { + callForAttention(); + } + + // TODO: Scrolls to the bottom of the channelTextArea on message received, this should be + // disabled + // when the user has scrolled up + channelTextArea.setCaretPosition(channelTextArea.getDocument().getLength()); + messageQueueInProgress = false; + } + } catch (InterruptedException e) + { + Constants.LOGGER.log(Level.WARNING, e.getLocalizedMessage()); } - } catch (InterruptedException e) - { - Constants.LOGGER.log(Level.WARNING, e.getLocalizedMessage()); } } - }).start(); + }); + } @@ -630,20 +642,25 @@ public void addToUsersList(final String channel, final String[] users) // Adds a single user, good for when a user joins the channel public void addToUsersList(final String channel, final String user) { - // Removed as Runnable(), not sure it was necessary - String thisUser = user; - if (user.startsWith(":")) - thisUser = user.substring(1); + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + String thisUser = user; + if (user.startsWith(":")) + thisUser = user.substring(1); - IRCUser newUser = getServer().getIRCUser(thisUser); + IRCUser newUser = getServer().getIRCUser(thisUser); - if (!usersArray.contains(newUser)) - { - usersArray.add(newUser); - usersList.setSelectedIndex(0); - createEvent("++ " + thisUser + " has entered " + channel); - usersListModel.sort(); - } + if (!usersArray.contains(newUser)) + { + usersArray.add(newUser); + usersList.setSelectedIndex(0); + createEvent("++ " + thisUser + " has entered " + channel); + usersListModel.sort(); + } + } + }); } public String getChannelTopic(String roomName) From 8e4c334e520ee24cffee8d8a972cfa3e6d87766d Mon Sep 17 00:00:00 2001 From: matty_r Date: Wed, 11 Oct 2023 06:05:01 +1000 Subject: [PATCH 09/78] Some rafactoring --- src/urChatBasic/backend/Connection.java | 3 ++- src/urChatBasic/base/IRCRoomBase.java | 3 +-- src/urChatBasic/frontend/IRCPrivate.java | 8 ++++---- src/urChatBasic/tests/backend/DialogTests.java | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/urChatBasic/backend/Connection.java b/src/urChatBasic/backend/Connection.java index f7d35e8..f751ade 100644 --- a/src/urChatBasic/backend/Connection.java +++ b/src/urChatBasic/backend/Connection.java @@ -190,7 +190,8 @@ public void sendClientText(String clientText, String fromChannel) throws IOExcep String msgPrefix = ":"+ getServer().getNick()+"!~"+ getServer().getNick()+"@urchatclient"; clientMessage = messageHandler.new Message(msgPrefix + " " +outText); - gui.setCurrentTab(tempTextArray[1]); + // TODO: Set current tab to this new priv tab + // gui.setCurrentTab(tempTextArray[1]); } else if (clientText.toLowerCase().startsWith("/whois")) { outText = "WHOIS " + tempTextArray[1] + "\r\n"; diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index a21ab2d..903e8b2 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -513,8 +513,7 @@ public void run() // TODO: Re-add later? // addToUsersList(getName(), fromUser); // fromIRCUser = getCreatedUsers(fromUser); - // System.out.println(); - Constants.LOGGER.log(Level.WARNING, "Message from a user that isn't in the user list!"); + // Constants.LOGGER.log(Level.WARNING, "Message from a user that isn't in the user list!"); fromIRCUser = new IRCUser(server, fromUser); } } diff --git a/src/urChatBasic/frontend/IRCPrivate.java b/src/urChatBasic/frontend/IRCPrivate.java index 3f0bb27..c4addd1 100644 --- a/src/urChatBasic/frontend/IRCPrivate.java +++ b/src/urChatBasic/frontend/IRCPrivate.java @@ -42,12 +42,12 @@ public void actionPerformed(ActionEvent arg0) { if (!clientTextBox.getText().trim().isEmpty()) { - String messagePrefix = ""; if (!clientTextBox.getText().startsWith("/")) - messagePrefix = "/msg " + getName() + " "; - server.sendClientText(messagePrefix + clientTextBox.getText(), getName()); + { + String messagePrefix = "/msg " + getName() + " "; + clientTextBox.setText(messagePrefix + clientTextBox.getText()); + } } - clientTextBox.setText(""); } } } diff --git a/src/urChatBasic/tests/backend/DialogTests.java b/src/urChatBasic/tests/backend/DialogTests.java index 58e3d12..57f8bad 100644 --- a/src/urChatBasic/tests/backend/DialogTests.java +++ b/src/urChatBasic/tests/backend/DialogTests.java @@ -10,7 +10,7 @@ public class DialogTests { - protected boolean automateTests = false; + protected boolean automateTests = true; protected void utilFunction() { From 0361346b8d4da04e3e1a2cf379e7f055c852b3d0 Mon Sep 17 00:00:00 2001 From: matty_r Date: Wed, 11 Oct 2023 06:16:44 +1000 Subject: [PATCH 10/78] test --- src/urChatBasic/base/IRCRoomBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 903e8b2..80b46a5 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -416,7 +416,7 @@ public String getUser() { public void printText(String line, String fromUser) { try { messageQueue.put(new MessagePair(line, fromUser)); - + // test if(!messageQueueInProgress) handleMessageQueue(); From c3e918dc227c4a57ff2ed6de75edabc98fabf08f Mon Sep 17 00:00:00 2001 From: matty_r Date: Wed, 11 Oct 2023 06:17:21 +1000 Subject: [PATCH 11/78] test --- src/urChatBasic/base/IRCRoomBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 80b46a5..c6d5f64 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -416,7 +416,7 @@ public String getUser() { public void printText(String line, String fromUser) { try { messageQueue.put(new MessagePair(line, fromUser)); - // test + if(!messageQueueInProgress) handleMessageQueue(); From 914ad877c29df750e01ce5f9bffaa3f36c57d802 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 12 Oct 2023 06:38:13 +1000 Subject: [PATCH 12/78] Add an uncaught exception handler to log out to the errors log --- src/urChatBasic/backend/LookAndFeelLoader.java | 2 +- .../backend/utils/URUncaughtExceptionHandler.java | 12 ++++++++++++ src/urChatBasic/frontend/DriverGUI.java | 3 ++- src/urChatBasic/frontend/UserGUI.java | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/urChatBasic/backend/utils/URUncaughtExceptionHandler.java diff --git a/src/urChatBasic/backend/LookAndFeelLoader.java b/src/urChatBasic/backend/LookAndFeelLoader.java index 9dcc015..b9e640f 100644 --- a/src/urChatBasic/backend/LookAndFeelLoader.java +++ b/src/urChatBasic/backend/LookAndFeelLoader.java @@ -14,7 +14,7 @@ import javax.swing.UIManager; import urChatBasic.base.Constants; -public class LookAndFeelLoader { +public class LookAndFeelLoader { public URLClassLoader cl; public LookAndFeelLoader(ClassLoader parentLoader) throws IOException { diff --git a/src/urChatBasic/backend/utils/URUncaughtExceptionHandler.java b/src/urChatBasic/backend/utils/URUncaughtExceptionHandler.java new file mode 100644 index 0000000..f7c944f --- /dev/null +++ b/src/urChatBasic/backend/utils/URUncaughtExceptionHandler.java @@ -0,0 +1,12 @@ +package urChatBasic.backend.utils; + +import java.util.logging.Level; +import urChatBasic.base.Constants; + +public class URUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { + + @Override + public void uncaughtException(Thread t, Throwable e) { + Constants.LOGGER.log(Level.SEVERE, "Uncaught exception in thread: " + t.getName(), e); + } +} \ No newline at end of file diff --git a/src/urChatBasic/frontend/DriverGUI.java b/src/urChatBasic/frontend/DriverGUI.java index b27e969..6326163 100644 --- a/src/urChatBasic/frontend/DriverGUI.java +++ b/src/urChatBasic/frontend/DriverGUI.java @@ -11,6 +11,7 @@ import javax.swing.JFrame; import javax.swing.SwingUtilities; import urChatBasic.backend.LookAndFeelLoader; +import urChatBasic.backend.utils.URUncaughtExceptionHandler; import urChatBasic.base.Constants; public class DriverGUI @@ -33,13 +34,13 @@ public static void main(String[] args) throws IOException LookAndFeelLoader lafLoader = new LookAndFeelLoader(Thread.currentThread().getContextClassLoader()); contextClassLoader = lafLoader.cl; Thread.currentThread().setContextClassLoader(contextClassLoader); + Thread.currentThread().setUncaughtExceptionHandler(new URUncaughtExceptionHandler()); createGUI(); startGUI(); } - final public static String getMemoryReport() { final Runtime r = Runtime.getRuntime(); diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index f6b952e..1f821c4 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -12,6 +12,7 @@ import javax.swing.*; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.event.*; +import urChatBasic.backend.utils.URUncaughtExceptionHandler; import urChatBasic.base.Constants; import urChatBasic.base.IRCRoomBase; import urChatBasic.base.IRCServerBase; @@ -1803,6 +1804,8 @@ public void run() { // Auto-generated method stub Thread.currentThread().setContextClassLoader(DriverGUI.contextClassLoader); + Thread.currentThread().setUncaughtExceptionHandler(new URUncaughtExceptionHandler()); + setNewLAF(((LookAndFeelInfo) lafOptions.getSelectedItem()).getClassName()); } } From 964562b21ff6c75ee000fd39a3dbd5f886cd7293 Mon Sep 17 00:00:00 2001 From: matty_r Date: Sun, 15 Oct 2023 07:05:57 +1000 Subject: [PATCH 13/78] prelim work on concurrent hashmap for the usersArray --- src/urChatBasic/base/IRCRoomBase.java | 58 ++++++++++--------------- src/urChatBasic/frontend/IRCServer.java | 4 +- 2 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index c6d5f64..bf06f7b 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.prefs.Preferences; import javax.swing.*; @@ -94,8 +95,8 @@ public class IRCRoomBase extends JPanel // Users list area // TODO: Users should be created per Server, and instead have a property to hold what channels // they're in - private List usersArray = new ArrayList(); - private UsersListModel usersListModel = new UsersListModel(usersArray); + private ConcurrentHashMap usersMap = new ConcurrentHashMap<>(); + private UsersListModel usersListModel = new UsersListModel(usersMap.values()); @SuppressWarnings("unchecked") private JList usersList = new JList(usersListModel); private JScrollPane userScroller = new JScrollPane(usersList); @@ -416,7 +417,7 @@ public String getUser() { public void printText(String line, String fromUser) { try { messageQueue.put(new MessagePair(line, fromUser)); - + if(!messageQueueInProgress) handleMessageQueue(); @@ -501,7 +502,7 @@ public void run() } StyledDocument doc = (StyledDocument) channelTextArea.getDocument(); - IRCUser fromIRCUser = getCreatedUsers(fromUser); + IRCUser fromIRCUser = getCreatedUser(fromUser); // If we received a message from a user that isn't in the channel // then add them to the users list. @@ -595,15 +596,8 @@ public void toggleEventTicker(Boolean showIt) * @param roomName * @return IRCChannel */ - public IRCUser getCreatedUsers(String userName) - { - for (IRCUser tempUser : usersArray) - { - if (tempUser.getName().equalsIgnoreCase(userName)) - return tempUser; - } ; - - return null; + public IRCUser getCreatedUser(String userName) { + return usersMap.get(userName.toLowerCase()); } public void disableFocus() @@ -631,8 +625,11 @@ public void addToUsersList(final String channel, final String[] users) IRCUser newUser = getServer().getIRCUser(tempUserName); - if (!usersArray.contains(newUser)) - usersArray.add(newUser); + if (null != getCreatedUser(tempUserName)) + { + usersMap.put(newUser.getName().toLowerCase(), newUser); + usersListModel.addElement(newUser); + } } } usersListModel.sort(); @@ -651,11 +648,12 @@ public void run() IRCUser newUser = getServer().getIRCUser(thisUser); - if (!usersArray.contains(newUser)) + if (null != getCreatedUser(thisUser)) { - usersArray.add(newUser); + usersMap.put(newUser.getName().toLowerCase(), newUser); usersList.setSelectedIndex(0); createEvent("++ " + thisUser + " has entered " + channel); + usersListModel.addElement(newUser); usersListModel.sort(); } } @@ -684,28 +682,17 @@ public void run() thisUser = user.substring(1); - int index = 0; - while (index < usersArray.size()) - { - if (usersArray.get(index).getName().matches(thisUser)) - { - usersArray.remove(index); - createEvent("-- " + thisUser + " has quit " + channel); - } else - { - index++; - } - } - + usersMap.remove(thisUser.toLowerCase()); + usersListModel.removeUser(thisUser); usersListModel.sort(); } }); } /** Clear the users list */ - public void clearUsersList(String channel) + public void clearUsersList() { - usersArray.clear(); + usersMap.clear(); } @@ -744,7 +731,7 @@ public void renameUser(final String oldUserName, final String newUserName) { public void run() { - IRCUser tempUser = getCreatedUsers(oldUserName); + IRCUser tempUser = getCreatedUser(oldUserName); if (tempUser != null) { createEvent("!! " + oldUserName + " changed name to " + newUserName); @@ -1066,9 +1053,8 @@ public void keyPressed(KeyEvent e) } // If usersArray and clientText isn't empty. - if (usersArray.size() > 0 && clientTextBox.getText().length() > 0) - { - usersArray.stream() + if (!usersMap.isEmpty() && clientTextBox.getText().length() > 0) { + usersMap.values().stream() .filter(user -> user.getName().toLowerCase().replace("@", "") .startsWith(startingCharacters.toLowerCase())) .forEach(user -> autoCompleteNames.add(user.getName())); diff --git a/src/urChatBasic/frontend/IRCServer.java b/src/urChatBasic/frontend/IRCServer.java index 00aa43b..608a6d5 100644 --- a/src/urChatBasic/frontend/IRCServer.java +++ b/src/urChatBasic/frontend/IRCServer.java @@ -371,8 +371,8 @@ public String getName() public IRCUser getIRCUser(String userName) { for (IRCRoomBase tempChannel : createdRooms) - if (tempChannel.getCreatedUsers(userName) != null) - return tempChannel.getCreatedUsers(userName); + if (tempChannel.getCreatedUser(userName) != null) + return tempChannel.getCreatedUser(userName); return new IRCUser(this, userName); } From 98ad78218b9aead0839b10d21df769cc73e833b1 Mon Sep 17 00:00:00 2001 From: matty_r Date: Mon, 16 Oct 2023 06:47:08 +1000 Subject: [PATCH 14/78] Refactoring --- src/urChatBasic/base/IRCRoomBase.java | 65 +++++++------------- src/urChatBasic/frontend/IRCServer.java | 10 +-- src/urChatBasic/frontend/UsersListModel.java | 28 ++++++--- 3 files changed, 43 insertions(+), 60 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index bf06f7b..d194a23 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -96,7 +96,7 @@ public class IRCRoomBase extends JPanel // TODO: Users should be created per Server, and instead have a property to hold what channels // they're in private ConcurrentHashMap usersMap = new ConcurrentHashMap<>(); - private UsersListModel usersListModel = new UsersListModel(usersMap.values()); + private UsersListModel usersListModel = new UsersListModel(); @SuppressWarnings("unchecked") private JList usersList = new JList(usersListModel); private JScrollPane userScroller = new JScrollPane(usersList); @@ -611,53 +611,34 @@ public void enableFocus() } // Adds users to the list in the users array[] - public void addToUsersList(final String channel, final String[] users) - { - // Removed as Runnable(), not sure it was necessary - // TODO: maybe readd Runnable - if (users.length >= 0 && null != getServer()) - { - for (int x = 0; x < users.length; x++) - { - String tempUserName = users[x]; - if (users[x].startsWith(":")) - tempUserName = tempUserName.substring(1); - - IRCUser newUser = getServer().getIRCUser(tempUserName); - - if (null != getCreatedUser(tempUserName)) - { - usersMap.put(newUser.getName().toLowerCase(), newUser); - usersListModel.addElement(newUser); + public void addToUsersList(final String[] users) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + // Removed as Runnable(), not sure it was necessary + // TODO: maybe readd Runnable + if (users.length >= 0 && null != getServer()) { + for (int x = 0; x < users.length; x++) { + String tempUserName = users[x]; + if (users[x].startsWith(":")) + tempUserName = tempUserName.substring(1); + + IRCUser newUser = getServer().getIRCUser(tempUserName); + + if (null != newUser) { + usersMap.put(newUser.getName().toLowerCase(), newUser); + usersListModel.addUser(newUser); + } + } } + usersListModel.sort(); } - } - usersListModel.sort(); + }); } // Adds a single user, good for when a user joins the channel - public void addToUsersList(final String channel, final String user) + public void addToUsersList(final String user) { - SwingUtilities.invokeLater(new Runnable() - { - public void run() - { - String thisUser = user; - if (user.startsWith(":")) - thisUser = user.substring(1); - - IRCUser newUser = getServer().getIRCUser(thisUser); - - if (null != getCreatedUser(thisUser)) - { - usersMap.put(newUser.getName().toLowerCase(), newUser); - usersList.setSelectedIndex(0); - createEvent("++ " + thisUser + " has entered " + channel); - usersListModel.addElement(newUser); - usersListModel.sort(); - } - } - }); + addToUsersList(new String[]{user}); } public String getChannelTopic(String roomName) diff --git a/src/urChatBasic/frontend/IRCServer.java b/src/urChatBasic/frontend/IRCServer.java index 608a6d5..3ce66c9 100644 --- a/src/urChatBasic/frontend/IRCServer.java +++ b/src/urChatBasic/frontend/IRCServer.java @@ -590,7 +590,7 @@ public void addToUsersList(final String channelName, final String[] users) { IRCChannel tempChannel = getCreatedChannel(channelName); if (tempChannel != null) - tempChannel.addToUsersList(tempChannel.getName(), users); + tempChannel.addToUsersList(users); } } @@ -603,13 +603,7 @@ public void addToUsersList(final String channelName, final String[] users) @Override public void addToUsersList(final String channelName, final String user) { - String thisUser = user; - if (user.startsWith(":")) - thisUser = user.substring(1); - - IRCChannel tempChannel = getCreatedChannel(channelName); - if (tempChannel != null) - tempChannel.addToUsersList(tempChannel.getName(), thisUser); + addToUsersList(channelName, new String[]{user}); } diff --git a/src/urChatBasic/frontend/UsersListModel.java b/src/urChatBasic/frontend/UsersListModel.java index b7e15b0..13b206f 100644 --- a/src/urChatBasic/frontend/UsersListModel.java +++ b/src/urChatBasic/frontend/UsersListModel.java @@ -4,22 +4,17 @@ import java.util.List; import java.util.Collections; -import javax.swing.DefaultListModel; +import javax.swing.AbstractListModel; @SuppressWarnings("rawtypes") -public class UsersListModel extends DefaultListModel +public class UsersListModel extends AbstractListModel { /** * */ private static final long serialVersionUID = 1L; // ArrayList users; - List users = new ArrayList(); - - public UsersListModel(List array) - { - users = array; - } + List users = new ArrayList(); public int getSize() { @@ -31,7 +26,21 @@ public IRCUser getElementAt(int index) return (IRCUser) users.get(index); } - @SuppressWarnings("unchecked") + public void addUser(IRCUser newUser) + { + users.add(newUser); + } + + public void removeUser(String userName) + { + users.removeIf(n -> n.getName().equalsIgnoreCase(userName)); + } + + public void removeUser(IRCUser targetUser) + { + users.remove(targetUser); + } + public List getUsersList() { return users; @@ -48,7 +57,6 @@ public void getSortedList(ArrayList array) users = array; } - @SuppressWarnings("unchecked") public void sort() { Collections.sort(users); From da08de50c11a213597d8a1b1bfd3dfb6a7e99e8e Mon Sep 17 00:00:00 2001 From: matty_r Date: Tue, 17 Oct 2023 06:18:18 +1000 Subject: [PATCH 15/78] Fixes #61. The bug was only apparent during testing where sending a privmsg to your own account. Instead of printing the message directly to the screen, we just wait to receive it from the server. --- src/urChatBasic/backend/Connection.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/urChatBasic/backend/Connection.java b/src/urChatBasic/backend/Connection.java index f751ade..e3ade07 100644 --- a/src/urChatBasic/backend/Connection.java +++ b/src/urChatBasic/backend/Connection.java @@ -180,15 +180,14 @@ public void sendClientText(String clientText, String fromChannel) throws IOExcep outText = "PRIVMSG " + tempTextArray[1] + " :" + clientText.replace("/msg " + tempTextArray[1] + " ", "") + "\r\n"; - // if (clientText.toLowerCase().startsWith("/msg nickserv identify")) - // { - // clientText = "*** HIDDEN NICKSERV IDENTIFY ***"; - // } - // server.printPrivateText(tempTextArray[1], clientText.replace("/msg " + tempTextArray[1] + " ", ""),getServer().getNick()); String msgPrefix = ":"+ getServer().getNick()+"!~"+ getServer().getNick()+"@urchatclient"; - clientMessage = messageHandler.new Message(msgPrefix + " " +outText); + + if(!tempTextArray[1].equalsIgnoreCase(getServer().getNick())) + { + clientMessage = messageHandler.new Message(msgPrefix + " " +outText); + } // TODO: Set current tab to this new priv tab // gui.setCurrentTab(tempTextArray[1]); From 6e296b50004ff2f074049bb64a096af0cdb75f89 Mon Sep 17 00:00:00 2001 From: matty_r Date: Tue, 17 Oct 2023 06:31:46 +1000 Subject: [PATCH 16/78] Fixes #63 by adding a confirmation dialog to open the link. The dialog takes focus, then focus is returned to the main window which sets the focus into the textbox. --- src/urChatBasic/frontend/LineFormatter.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 7768e80..622baf9 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -6,10 +6,12 @@ import java.awt.event.ActionEvent; import java.net.URL; import java.util.Iterator; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.AbstractAction; +import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.UIManager; import javax.swing.text.AttributeSet; @@ -19,6 +21,7 @@ import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import urChatBasic.base.Constants; +import urChatBasic.frontend.dialogs.YesNoDialog; import urChatBasic.frontend.utils.URColour; public class LineFormatter @@ -144,7 +147,15 @@ public void execute() { // TODO: This should really pop up a dialog to confirm you want to open the link try { - Desktop.getDesktop().browse(new URL(textLink).toURI()); + AtomicBoolean doOpenLink = new AtomicBoolean(false); + + YesNoDialog confirmOpenLink = new YesNoDialog("Are you sure you want to open "+textLink+"?", "Open Link", + JOptionPane.QUESTION_MESSAGE, e -> doOpenLink.set(e.getActionCommand().equalsIgnoreCase("Yes"))); + + confirmOpenLink.setVisible(true); + + if(doOpenLink.get()) + Desktop.getDesktop().browse(new URL(textLink).toURI()); } catch (Exception e) { e.printStackTrace(); } From 518b5e132cca8c373fd274a1da8e0838ae3626db Mon Sep 17 00:00:00 2001 From: matty_r Date: Thu, 19 Oct 2023 05:49:54 +1000 Subject: [PATCH 17/78] Prelim work for allowing clickable channel names --- src/urChatBasic/base/Constants.java | 2 +- src/urChatBasic/base/IRCRoomBase.java | 7 +- src/urChatBasic/frontend/LineFormatter.java | 2 + .../tests/backend/MessageHandlerTests.java | 69 +++++++++++++++++-- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/urChatBasic/base/Constants.java b/src/urChatBasic/base/Constants.java index bd93135..ab2d378 100644 --- a/src/urChatBasic/base/Constants.java +++ b/src/urChatBasic/base/Constants.java @@ -120,7 +120,7 @@ public class Constants public static final String END_MESSAGE = "\r\n"; // We 'must' match against http(s) in order to define the correct protocol to be used public static final String URL_REGEX = "((http:\\/\\/|https:\\/\\/)(www.)?(([a-zA-Z0-9-]){2,}\\.){1,4}([a-zA-Z]){2,6}(\\/([a-zA-Z-_\\/\\.0-9#:?=&;,]*)?)?)"; - + public static final String CHANNEL_REGEX = "#([^\s,]+)(?!,)"; // Used to identify a message to be printed from the Event ticker // like a "user joins room" type message public static final String EVENT_USER = "****"; diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index d194a23..ed7aea8 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -441,13 +441,12 @@ public void run() { try { + messageQueueInProgress = true; MessagePair messagePair = messageQueue.take(); - if(null != messagePair) - { - messageQueueInProgress = true; - } else + if(null == messagePair) { + messageQueueInProgress = false; continue; } diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 622baf9..484dce7 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -203,6 +203,8 @@ private SimpleAttributeSet getStyle(String styleName) return myStyle(); case "lowStyle": return lowStyle(); + case "urlStyle": + return urlStyle(); default: return defaultStyle(); } diff --git a/src/urChatBasic/tests/backend/MessageHandlerTests.java b/src/urChatBasic/tests/backend/MessageHandlerTests.java index bba6a61..47adca3 100644 --- a/src/urChatBasic/tests/backend/MessageHandlerTests.java +++ b/src/urChatBasic/tests/backend/MessageHandlerTests.java @@ -5,17 +5,23 @@ import urChatBasic.backend.Connection; import urChatBasic.backend.MessageHandler; import urChatBasic.backend.MessageHandler.Message; +import urChatBasic.base.Constants; import urChatBasic.base.IRCRoomBase; import urChatBasic.frontend.DriverGUI; import urChatBasic.frontend.IRCServer; import urChatBasic.frontend.IRCUser; +import urChatBasic.frontend.LineFormatter.ClickableText; import urChatBasic.frontend.UserGUI; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyledDocument; public class MessageHandlerTests { @@ -143,11 +149,10 @@ public void noticeMessage2() Message testMessage = testHandler.new Message(rawMessage); assertEquals("#channelname", testMessage.getChannel()); - // TODO create this test } @Test - public void handleChannelUrl() + public void handleChannelNoticeUrl() { String rawMessage = ":services. 328 userName #somechannel :https://somechannel.com/url"; Message testMessage = testHandler.new Message(rawMessage); @@ -257,11 +262,63 @@ public void emojiMessage() } @Test - public void urlMessage() + public void urlInMessage() throws BadLocationException, InterruptedException { // test displaying urls - String rawMessage = "https://i.imgur.com/somepicture.png"; - String rawMessage2 = "https://duckduckgo.com/?q=irc+urchat&kp=1&t=h_&ia=web"; - // TODO create this test + + String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG #somechannel :https://i.imgur.com/somepicture.png"; + // String rawMessage2 = "https://duckduckgo.com/?q=irc+urchat&kp=1&t=h_&ia=web"; + + Message testMessage = testHandler.new Message(rawMessage); + testHandler.parseMessage(testMessage); + StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); + + while(testChannel.messageQueueWorking()) + { + TimeUnit.SECONDS.sleep(1); + } + + String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] https://google.com" + // Should be urlStyle, i.e a clickable link + assertEquals("urlStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 19, testLine).getAttribute("name")); + } + + @Test + public void channelRegex() + { + // find and match against any URLs that may be in the text + String line = "join #urchatclient to test the regex"; + + Pattern pattern = Pattern.compile(Constants.CHANNEL_REGEX); + Matcher matcher = pattern.matcher(line); + + + String regexLine = ""; + while (matcher.find()) { + regexLine = line.substring(matcher.start(), matcher.end()); + } + + assertTrue(regexLine.equalsIgnoreCase("#urchatclient")); + } + + @Test + public void channelInMessage() throws BadLocationException, InterruptedException + { + // test displaying channel + + String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG #somechannel :Please join #urchatclient"; + + Message testMessage = testHandler.new Message(rawMessage); + testHandler.parseMessage(testMessage); + StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); + + while(testChannel.messageQueueWorking()) + { + TimeUnit.SECONDS.sleep(1); + } + + String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] Please join #urchatclient" + // Should be channel, i.e clickable name which allows you to join the channel + assertEquals("channelStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 19, testLine).getAttribute("name")); } } From f5dba3d9fbf4474c0549a686e1b255cc782d9675 Mon Sep 17 00:00:00 2001 From: matty_r Date: Sat, 21 Oct 2023 11:02:39 +1000 Subject: [PATCH 18/78] refactoring for clickable channel names --- src/urChatBasic/base/IRCRoomBase.java | 2 +- src/urChatBasic/frontend/LineFormatter.java | 114 +++++++++++++----- .../tests/backend/MessageHandlerTests.java | 13 +- 3 files changed, 94 insertions(+), 35 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index ed7aea8..0936ef2 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -173,7 +173,7 @@ private void initRoom() roomPrefs = gui.getFavouritesPath().node(getServer().getName()).node(roomName); fontDialog = new FontDialog(roomName, gui.getFont(), roomPrefs); - lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer().getNick()); + lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer()); } else { roomPrefs = gui.getFavouritesPath().node(roomName); diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 484dce7..742478c 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -5,7 +5,9 @@ import java.awt.Font; import java.awt.event.ActionEvent; import java.net.URL; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.regex.Matcher; @@ -21,6 +23,7 @@ import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import urChatBasic.base.Constants; +import urChatBasic.base.IRCServerBase; import urChatBasic.frontend.dialogs.YesNoDialog; import urChatBasic.frontend.utils.URColour; @@ -28,15 +31,27 @@ public class LineFormatter { private String myNick; private Font myFont; + private IRCServerBase myServer; public SimpleAttributeSet defaultStyle; public SimpleAttributeSet timeStyle; public SimpleAttributeSet nameStyle; public SimpleAttributeSet lineStyle; protected UserGUI gui = DriverGUI.gui; - public LineFormatter(Font myFont, String myNick) + public LineFormatter(Font myFont, final IRCServerBase server) { - this.myNick = myNick; + // myNick = server.getNick(); + + if(null != server) + { + myNick = server.getNick(); + myServer = server; + } + else + { + myNick = null; + } + this.myFont = myFont; defaultStyle = defaultStyle(); timeStyle = defaultStyle(); @@ -55,7 +70,7 @@ public SimpleAttributeSet defaultStyle() { SimpleAttributeSet defaultStyle = new SimpleAttributeSet(); defaultStyle.addAttribute("name", "defaultStyle"); - + defaultStyle.addAttribute("type", "default"); // get the contrasting colour of the background colour StyleConstants.setForeground(defaultStyle, URColour.getContrastColour(UIManager.getColor("Panel.background"))); StyleConstants.setFontFamily(defaultStyle, myFont.getFamily()); @@ -111,6 +126,16 @@ public SimpleAttributeSet urlStyle() return tempStyle; } + public SimpleAttributeSet channelStyle() + { + SimpleAttributeSet tempStyle = urlStyle(); + + tempStyle.addAttribute("name", "channelStyle"); + tempStyle.addAttribute("type", "channel"); + + return tempStyle; + } + public SimpleAttributeSet myStyle() { SimpleAttributeSet tempStyle = defaultStyle(); @@ -145,7 +170,6 @@ public void execute() { if (!textLink.isEmpty() && gui.isClickableLinksEnabled() && attributeSet.getAttribute("type").equals("url")) { - // TODO: This should really pop up a dialog to confirm you want to open the link try { AtomicBoolean doOpenLink = new AtomicBoolean(false); @@ -159,6 +183,24 @@ public void execute() } catch (Exception e) { e.printStackTrace(); } + } else if(!textLink.isEmpty() && attributeSet.getAttribute("type").equals("channel")) + { + try { + AtomicBoolean doJoinChannel = new AtomicBoolean(false); + + YesNoDialog confirmOpenLink = new YesNoDialog("Are you sure you want to join channel "+textLink+"?", "Join Channel", + JOptionPane.QUESTION_MESSAGE, e -> doJoinChannel.set(e.getActionCommand().equalsIgnoreCase("Yes"))); + + confirmOpenLink.setVisible(true); + + // TODO: Join channel + if(doJoinChannel.get()) + { + myServer.sendClientText("/join " + textLink, ""); + } + } catch (Exception e) { + e.printStackTrace(); + } } } @@ -205,12 +247,13 @@ private SimpleAttributeSet getStyle(String styleName) return lowStyle(); case "urlStyle": return urlStyle(); + case "channelStyle": + return channelStyle(); default: return defaultStyle(); } } - public void updateStyles(StyledDocument doc, int startPosition) { AttributeSet textStyle = doc.getCharacterElement(startPosition).getAttributes(); @@ -232,7 +275,6 @@ public void updateStyles(StyledDocument doc, int startPosition) } } - doc.setCharacterAttributes(styleStart, styleLength, matchingStyle, true); if((styleStart + styleLength) < doc.getLength()) @@ -297,8 +339,40 @@ public SimpleAttributeSet getStyleAtPosition(StyledDocument doc, int position, S position = position + getLinePosition(doc, relativeLine); AttributeSet textStyle = doc.getCharacterElement(position).getAttributes(); - String styleName = textStyle.getAttribute("name").toString(); - return getStyle(styleName); + + // String styleName = textStyle.getAttribute("name").toString(); + return new SimpleAttributeSet(textStyle); + } + + private String parseClickableText(StyledDocument doc, IRCUser fromUser) throws BadLocationException + { + HashMap regexStrings = new HashMap<>(); + regexStrings.put(Constants.URL_REGEX, urlStyle()); + regexStrings.put(Constants.CHANNEL_REGEX, channelStyle()); + final String line = getLatestLine(doc); + final int relativePosition = getLinePosition(doc, getLatestLine(doc)); + + for (Map.Entry entry : regexStrings.entrySet()) { + String regex = entry.getKey(); + SimpleAttributeSet linkStyle = entry.getValue(); + + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(line); + + // do stuff for each match + while (matcher.find()) { + + String clickableLine = line.substring(matcher.start(), matcher.end()); + linkStyle.addAttribute("clickableText", new ClickableText(clickableLine, linkStyle, fromUser)); + + int styleStart = relativePosition + matcher.start(); + int styleLength = matcher.end() - matcher.start(); + + doc.setCharacterAttributes(styleStart, styleLength, linkStyle, true); + } + } + + return line; } /** @@ -353,30 +427,12 @@ public void formattedDocument(StyledDocument doc, String timeLine, IRCUser fromU appendString(doc, "> ", lineStyle); - // find and match against any URLs that may be in the text - Pattern pattern = Pattern.compile(Constants.URL_REGEX); - Matcher matcher = pattern.matcher(line); - SimpleAttributeSet linkStyle = urlStyle(); - - while (matcher.find()) { - // pre http - appendString(doc, line.substring(0, matcher.start()), lineStyle); - - // http "clickableText" - String httpLine = line.substring(matcher.start(), matcher.end()); - linkStyle.addAttribute("clickableText", new ClickableText(httpLine, linkStyle, fromUser)); - appendString(doc, httpLine, linkStyle); - - // post http - line = line.substring(matcher.end()); - - // search again - matcher = pattern.matcher(line); - } - // print the remaining text appendString(doc, line, lineStyle); + // parse the outputted line for clickable text + parseClickableText(doc, fromUser); + appendString(doc, System.getProperty("line.separator"), lineStyle); } catch (BadLocationException e) { diff --git a/src/urChatBasic/tests/backend/MessageHandlerTests.java b/src/urChatBasic/tests/backend/MessageHandlerTests.java index 47adca3..e8a190b 100644 --- a/src/urChatBasic/tests/backend/MessageHandlerTests.java +++ b/src/urChatBasic/tests/backend/MessageHandlerTests.java @@ -21,7 +21,6 @@ import java.util.regex.Pattern; import javax.swing.text.BadLocationException; -import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyledDocument; public class MessageHandlerTests { @@ -305,10 +304,12 @@ public void channelRegex() public void channelInMessage() throws BadLocationException, InterruptedException { // test displaying channel + Message testMessage = testHandler.new Message(":someuser!~someuser@urchatclient PRIVMSG #somechannel :first line"); + testHandler.parseMessage(testMessage); - String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG #somechannel :Please join #urchatclient"; + String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG #somechannel :Please join #urchatclient and go to https://github.com/matty-r/urChat then go back to #anotherchannel"; - Message testMessage = testHandler.new Message(rawMessage); + testMessage = testHandler.new Message(rawMessage); testHandler.parseMessage(testMessage); StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); @@ -317,8 +318,10 @@ public void channelInMessage() throws BadLocationException, InterruptedException TimeUnit.SECONDS.sleep(1); } - String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] Please join #urchatclient" + String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // Should be channel, i.e clickable name which allows you to join the channel - assertEquals("channelStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 19, testLine).getAttribute("name")); + assertEquals("channelStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 33, testLine).getAttribute("name")); + assertEquals("urlStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 58, testLine).getAttribute("name")); + assertEquals("channelStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 110, testLine).getAttribute("name")); } } From 100e66272474cb265d0d0e635015bd9b8a1ed12c Mon Sep 17 00:00:00 2001 From: matty_r Date: Sun, 22 Oct 2023 06:22:46 +1000 Subject: [PATCH 19/78] Fix up clicking a room name in the server tab. Fixes #53. --- src/urChatBasic/backend/MessageHandler.java | 5 +++-- src/urChatBasic/base/IRCRoomBase.java | 5 +++++ src/urChatBasic/base/IRCServerBase.java | 2 ++ src/urChatBasic/frontend/IRCServer.java | 3 ++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/urChatBasic/backend/MessageHandler.java b/src/urChatBasic/backend/MessageHandler.java index 3d3c289..805faac 100644 --- a/src/urChatBasic/backend/MessageHandler.java +++ b/src/urChatBasic/backend/MessageHandler.java @@ -140,7 +140,7 @@ private void addRanges() rangeIDs.add(new IDRange(412, 415, new BadPrivateMessage())); rangeIDs.add(new IDRange(371, 376, new GeneralServerMessage())); rangeIDs.add(new IDRange(251, 256, new GeneralServerMessage())); - rangeIDs.add(new IDRange(471, 475, new JoinFailureMessage())); + rangeIDs.add(new IDRange(471, 477, new JoinFailureMessage())); } private void addSingles() @@ -149,7 +149,7 @@ private void addSingles() singleIDs.add(new IDSingle(353, new UsersListMessage())); singleIDs.add(new IDSingle(322, new CommandResponseMessage())); singleIDs.add(new IDSingle((new int[] {311, 319, 312, 317, 318, 301, 671, 330, 338, 378}), new WhoIsMessage())); - singleIDs.add(new IDSingle((new int[] {004, 265, 266, 250, 422, 477, 331, 900}), new GeneralServerMessage())); + singleIDs.add(new IDSingle((new int[] {004, 265, 266, 250, 422, 331, 900}), new GeneralServerMessage())); singleIDs.add(new IDSingle(366, new GeneralChannelMessage())); singleIDs.add(new IDSingle((new int[] {432, 433, 451}), new InvalidNickMessage())); singleIDs.add(new IDSingle((new int[] {401, 403}), new NoSuchChannelMessage())); @@ -532,6 +532,7 @@ public class JoinFailureMessage implements MessageBase public void messageExec(Message myMessage) { printServerText(myMessage.body); + serverBase.callForAttention(); } } diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 0936ef2..5de0fe9 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -238,6 +238,11 @@ public FontPanel getFontPanel() return fontDialog.getFontPanel(); } + public void resetLineFormatter() + { + lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer()); + } + private void setupMainTextArea() { channelScroll.setPreferredSize( diff --git a/src/urChatBasic/base/IRCServerBase.java b/src/urChatBasic/base/IRCServerBase.java index d138bf7..ee94adb 100644 --- a/src/urChatBasic/base/IRCServerBase.java +++ b/src/urChatBasic/base/IRCServerBase.java @@ -161,4 +161,6 @@ public interface IRCServerBase * @param newUser */ public abstract void renameUser (String oldUserName, String newUserName); + + public void callForAttention(); } diff --git a/src/urChatBasic/frontend/IRCServer.java b/src/urChatBasic/frontend/IRCServer.java index 3ce66c9..f987417 100644 --- a/src/urChatBasic/frontend/IRCServer.java +++ b/src/urChatBasic/frontend/IRCServer.java @@ -60,6 +60,8 @@ public IRCServer(String serverName, String nick, String login, String password, String proxyPort, Boolean useSOCKS) { super(serverName); + setServer(this); + resetLineFormatter(); myMenu = new ServerPopUp(); hideUsersList(); @@ -448,7 +450,6 @@ public IRCRoomBase getCreatedRoom(String roomName, boolean asPrivate) return null; } - /* * (non-Javadoc) * From 98fa466a4cee2f5d032c20506544e5426b09f244 Mon Sep 17 00:00:00 2001 From: matty_r Date: Mon, 23 Oct 2023 06:31:58 +1000 Subject: [PATCH 20/78] Begin tidying up the interface a bit --- src/urChatBasic/frontend/LineFormatter.java | 1 - src/urChatBasic/frontend/UserGUI.java | 397 +++++++++--------- .../frontend/components/ProfilePicker.java | 7 + 3 files changed, 217 insertions(+), 188 deletions(-) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 742478c..701c281 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -193,7 +193,6 @@ public void execute() confirmOpenLink.setVisible(true); - // TODO: Join channel if(doJoinChannel.get()) { myServer.sendClientText("/join " + textLink, ""); diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 1f821c4..0c18dfb 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -50,8 +50,8 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase private ProfilePicker profilePicker; // Client Options Panel - private static final JPanel optionsClientPanel = new JPanel(); - private static final JScrollPane clientScroller = new JScrollPane(optionsClientPanel); + private static final JPanel interfacePanel = new JPanel(); + private static final JScrollPane interfaceScroller = new JScrollPane(interfacePanel); private static final JLabel lafOptionsLabel = new JLabel("Theme:"); private static final JComboBox lafOptions = new JComboBox(UIManager.getInstalledLookAndFeels()); @@ -80,8 +80,12 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase new JSlider(JSlider.HORIZONTAL, TICKER_DELAY_MIN, TICKER_DELAY_MAX, TICKER_DELAY_INIT); // Server Options Panel - private static final JPanel serverOptionsPanel = new JPanel(); - private static final JScrollPane serverScroller = new JScrollPane(serverOptionsPanel); + private static final JPanel connectionPanel = new JPanel(); + private static final JScrollPane connectionScroller = new JScrollPane(connectionPanel); + + // Appearance Options Panel + private static final JPanel appearancePanel = new JPanel(); + private static final JScrollPane appearanceScroller = new JScrollPane(appearancePanel); // Identification private static final JLabel userNameLabel = new JLabel("Nick:"); @@ -454,8 +458,9 @@ private void setupOptionsPanel() { optionsMainPanel.setLayout(new BorderLayout()); - optionsArray.addElement("Server"); - optionsArray.addElement("Client"); + optionsArray.addElement("Connection"); + optionsArray.addElement("Interface"); + optionsArray.addElement("Appearance"); setupLeftOptionsPanel(); setupRightOptionsPanel(); @@ -464,11 +469,9 @@ private void setupOptionsPanel() optionsMainPanel.add(optionsRightPanel, BorderLayout.CENTER); optionsList.setSelectedIndex(OPTIONS_INDEX); - // optionsClientPanel.setPreferredSize(new Dimension(500, 0)); - // serverOptionsPanel.setPreferredSize(new Dimension(200, 0)); - - optionsRightPanel.add(serverScroller, "Server"); - optionsRightPanel.add(clientScroller, "Client"); + optionsRightPanel.add(connectionScroller, "Connection"); + optionsRightPanel.add(interfaceScroller, "Interface"); + optionsRightPanel.add(appearanceScroller, "Appearance"); } /** @@ -502,89 +505,89 @@ private void setupRightOptionsPanel() // optionsRightPanel.setBackground(Color.BLACK); optionsRightPanel.setLayout(new CardLayout()); - setupServerOptionsPanelComponents(); - setupClientOptionsPanelComponents(); + setupConnectionPanel(); + setupInterfacePanel(); + setupAppearancePanel(); } - /** * Add the components to the Server Options Panel. */ - private void setupServerOptionsPanelComponents() + private void setupConnectionPanel() { - // serverOptionsPanel.setLayout(new BoxLayout(serverOptionsPanel, BoxLayout.PAGE_AXIS)); - setupServerOptionsLayout(); + // connectionPanel.setLayout(new BoxLayout(connectionPanel, BoxLayout.PAGE_AXIS)); + setupConnectionLayout(); // User stuff - serverOptionsPanel.add(userNameLabel); - serverOptionsPanel.add(userNameTextField); + connectionPanel.add(userNameLabel); + connectionPanel.add(userNameTextField); // userNameTextField.setPreferredSize(new Dimension(100, 24)); // userNameTextField.setMinimumSize(new Dimension(100, 0)); - serverOptionsPanel.add(realNameLabel); - serverOptionsPanel.add(realNameTextField); + connectionPanel.add(realNameLabel); + connectionPanel.add(realNameTextField); // realNameTextField.setMinimumSize(new Dimension(100, 0)); - serverOptionsPanel.add(authenticationTypeLabel); - serverOptionsPanel.add(authenticationTypeChoice); + connectionPanel.add(authenticationTypeLabel); + connectionPanel.add(authenticationTypeChoice); authenticationTypeChoice.addActionListener(new UCAuthTypeComboBoxChangeHandler()); // authenticationTypeChoice.setPreferredSize(new Dimension(200, 20)); - serverOptionsPanel.add(passwordLabel); - serverOptionsPanel.add(passwordTextField); + connectionPanel.add(passwordLabel); + connectionPanel.add(passwordTextField); passwordTextField.setEchoChar('*'); - serverOptionsPanel.add(rememberPassLabel); - serverOptionsPanel.add(rememberPassCheckBox); + connectionPanel.add(rememberPassLabel); + connectionPanel.add(rememberPassCheckBox); // passwordTextField.setPreferredSize(new Dimension(200, 20)); // Server Stuff - serverOptionsPanel.add(serverNameLabel); - serverOptionsPanel.add(servernameTextField); + connectionPanel.add(serverNameLabel); + connectionPanel.add(servernameTextField); // servernameTextField.setPreferredSize(new Dimension(100, 20)); - serverOptionsPanel.add(serverPortLabel); - serverOptionsPanel.add(serverPortTextField); + connectionPanel.add(serverPortLabel); + connectionPanel.add(serverPortTextField); // serverPortTextField.setPreferredSize(new Dimension(50, 20)); - serverOptionsPanel.add(serverUseTLSLabel); - serverOptionsPanel.add(serverTLSCheckBox); + connectionPanel.add(serverUseTLSLabel); + connectionPanel.add(serverTLSCheckBox); // serverTLSCheckBox.setPreferredSize(new Dimension(50, 20)); // Proxy Stuff - serverOptionsPanel.add(proxyHostLabel); - serverOptionsPanel.add(proxyHostNameTextField); + connectionPanel.add(proxyHostLabel); + connectionPanel.add(proxyHostNameTextField); // proxyHostNameTextField.setPreferredSize(new Dimension(100, 20)); - serverOptionsPanel.add(proxyPortLabel); - serverOptionsPanel.add(proxyPortTextField); + connectionPanel.add(proxyPortLabel); + connectionPanel.add(proxyPortTextField); // proxyPortTextField.setPreferredSize(new Dimension(50, 20)); - serverOptionsPanel.add(serverUseProxyLabel); - serverOptionsPanel.add(serverProxyCheckBox); + connectionPanel.add(serverUseProxyLabel); + connectionPanel.add(serverProxyCheckBox); // serverProxyCheckBox.setPreferredSize(new Dimension(50, 20)); // Channel Stuff - serverOptionsPanel.add(firstChannelLabel); - serverOptionsPanel.add(firstChannelTextField); + connectionPanel.add(firstChannelLabel); + connectionPanel.add(firstChannelTextField); // firstChannelTextField.setPreferredSize(new Dimension(100, 20)); - serverOptionsPanel.add(connectButton); + connectionPanel.add(connectButton); connectButton.addActionListener(new ConnectPressed()); - serverOptionsPanel.add(autoConnectToFavourites); + connectionPanel.add(autoConnectToFavourites); favouritesScroller.setPreferredSize(new Dimension(200, 100)); favouritesList.addMouseListener(new FavouritesPopClickListener()); - serverOptionsPanel.add(favouritesScroller); + connectionPanel.add(favouritesScroller); } /** * Aligns components on the Server Options Panel */ - private void setupServerOptionsLayout() + private void setupConnectionLayout() { - SpringLayout serverLayout = new SpringLayout(); - serverOptionsPanel.setLayout(serverLayout); + SpringLayout connectionLayout = new SpringLayout(); + connectionPanel.setLayout(connectionLayout); // Used to make it more obvious what is going on - // and perhaps more readable. @@ -598,173 +601,168 @@ private void setupServerOptionsLayout() // Components are aligned off the top label // User stuff - serverLayout.putConstraint(SpringLayout.NORTH, userNameLabel, TOP_SPACING * 2, SpringLayout.NORTH, - serverOptionsPanel); - serverLayout.putConstraint(SpringLayout.WEST, userNameLabel, LEFT_SPACING * 2, SpringLayout.WEST, - serverOptionsPanel); + connectionLayout.putConstraint(SpringLayout.NORTH, userNameLabel, TOP_SPACING * 2, SpringLayout.NORTH, + connectionPanel); + connectionLayout.putConstraint(SpringLayout.WEST, userNameLabel, LEFT_SPACING * 2, SpringLayout.WEST, + connectionPanel); - serverLayout.putConstraint(SpringLayout.NORTH, userNameTextField, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, userNameTextField, TOP_ALIGNED, SpringLayout.SOUTH, userNameLabel); - serverLayout.putConstraint(SpringLayout.WEST, userNameTextField, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, userNameTextField, LEFT_ALIGNED, SpringLayout.WEST, userNameLabel); - serverLayout.putConstraint(SpringLayout.NORTH, realNameLabel, TOP_SPACING, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, realNameLabel, TOP_SPACING, SpringLayout.SOUTH, userNameTextField); - serverLayout.putConstraint(SpringLayout.WEST, realNameLabel, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, realNameLabel, LEFT_ALIGNED, SpringLayout.WEST, userNameTextField); - serverLayout.putConstraint(SpringLayout.NORTH, realNameTextField, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, realNameTextField, TOP_ALIGNED, SpringLayout.SOUTH, realNameLabel); - serverLayout.putConstraint(SpringLayout.WEST, realNameTextField, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, realNameTextField, LEFT_ALIGNED, SpringLayout.WEST, realNameLabel); - serverLayout.putConstraint(SpringLayout.EAST, realNameTextField, RIGHT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.EAST, realNameTextField, RIGHT_ALIGNED, SpringLayout.EAST, userNameTextField); // Authentication Stuff - serverLayout.putConstraint(SpringLayout.NORTH, authenticationTypeLabel, TOP_SPACING, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, authenticationTypeLabel, TOP_SPACING, SpringLayout.SOUTH, realNameTextField); - serverLayout.putConstraint(SpringLayout.WEST, authenticationTypeLabel, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, authenticationTypeLabel, LEFT_ALIGNED, SpringLayout.WEST, realNameTextField); - serverLayout.putConstraint(SpringLayout.NORTH, authenticationTypeChoice, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, authenticationTypeChoice, TOP_ALIGNED, SpringLayout.SOUTH, authenticationTypeLabel); - serverLayout.putConstraint(SpringLayout.WEST, authenticationTypeChoice, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, authenticationTypeChoice, LEFT_ALIGNED, SpringLayout.WEST, authenticationTypeLabel); - serverLayout.putConstraint(SpringLayout.EAST, authenticationTypeChoice, RIGHT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.EAST, authenticationTypeChoice, RIGHT_ALIGNED, SpringLayout.EAST, realNameTextField); // Password - serverLayout.putConstraint(SpringLayout.NORTH, passwordLabel, TOP_SPACING, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, passwordLabel, TOP_SPACING, SpringLayout.SOUTH, authenticationTypeChoice); - serverLayout.putConstraint(SpringLayout.WEST, passwordLabel, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, passwordLabel, LEFT_ALIGNED, SpringLayout.WEST, authenticationTypeChoice); - serverLayout.putConstraint(SpringLayout.NORTH, passwordTextField, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, passwordTextField, TOP_ALIGNED, SpringLayout.SOUTH, passwordLabel); - serverLayout.putConstraint(SpringLayout.WEST, passwordTextField, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, passwordTextField, LEFT_ALIGNED, SpringLayout.WEST, passwordLabel); - serverLayout.putConstraint(SpringLayout.EAST, passwordTextField, RIGHT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.EAST, passwordTextField, RIGHT_ALIGNED, SpringLayout.EAST, authenticationTypeChoice); - serverLayout.putConstraint(SpringLayout.NORTH, rememberPassLabel, TOP_ALIGNED, SpringLayout.NORTH, + connectionLayout.putConstraint(SpringLayout.NORTH, rememberPassLabel, TOP_ALIGNED, SpringLayout.NORTH, passwordLabel); - serverLayout.putConstraint(SpringLayout.WEST, rememberPassLabel, LEFT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.WEST, rememberPassLabel, LEFT_ALIGNED, SpringLayout.EAST, passwordTextField); - serverLayout.putConstraint(SpringLayout.NORTH, rememberPassCheckBox, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, rememberPassCheckBox, TOP_ALIGNED, SpringLayout.SOUTH, rememberPassLabel); - serverLayout.putConstraint(SpringLayout.WEST, rememberPassCheckBox, LEFT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.WEST, rememberPassCheckBox, LEFT_ALIGNED, SpringLayout.EAST, passwordTextField); // Server stuff - serverLayout.putConstraint(SpringLayout.NORTH, serverNameLabel, TOP_SPACING, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, serverNameLabel, TOP_SPACING, SpringLayout.SOUTH, passwordTextField); - serverLayout.putConstraint(SpringLayout.WEST, serverNameLabel, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, serverNameLabel, LEFT_ALIGNED, SpringLayout.WEST, passwordTextField); - serverLayout.putConstraint(SpringLayout.NORTH, servernameTextField, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, servernameTextField, TOP_ALIGNED, SpringLayout.SOUTH, serverNameLabel); - serverLayout.putConstraint(SpringLayout.WEST, servernameTextField, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, servernameTextField, LEFT_ALIGNED, SpringLayout.WEST, serverNameLabel); - serverLayout.putConstraint(SpringLayout.NORTH, serverPortLabel, TOP_ALIGNED, SpringLayout.NORTH, + connectionLayout.putConstraint(SpringLayout.NORTH, serverPortLabel, TOP_ALIGNED, SpringLayout.NORTH, serverNameLabel); - serverLayout.putConstraint(SpringLayout.WEST, serverPortLabel, LEFT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.WEST, serverPortLabel, LEFT_ALIGNED, SpringLayout.EAST, servernameTextField); - serverLayout.putConstraint(SpringLayout.NORTH, serverPortTextField, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, serverPortTextField, TOP_ALIGNED, SpringLayout.SOUTH, serverPortLabel); - serverLayout.putConstraint(SpringLayout.WEST, serverPortTextField, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, serverPortTextField, LEFT_ALIGNED, SpringLayout.WEST, serverPortLabel); - serverLayout.putConstraint(SpringLayout.NORTH, serverUseTLSLabel, TOP_ALIGNED, SpringLayout.NORTH, + connectionLayout.putConstraint(SpringLayout.NORTH, serverUseTLSLabel, TOP_ALIGNED, SpringLayout.NORTH, serverPortLabel); - serverLayout.putConstraint(SpringLayout.WEST, serverUseTLSLabel, LEFT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.WEST, serverUseTLSLabel, LEFT_ALIGNED, SpringLayout.EAST, serverPortTextField); - serverLayout.putConstraint(SpringLayout.NORTH, serverTLSCheckBox, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, serverTLSCheckBox, TOP_ALIGNED, SpringLayout.SOUTH, serverUseTLSLabel); - serverLayout.putConstraint(SpringLayout.WEST, serverTLSCheckBox, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, serverTLSCheckBox, LEFT_ALIGNED, SpringLayout.WEST, serverUseTLSLabel); // Proxy stuff - serverLayout.putConstraint(SpringLayout.NORTH, proxyHostLabel, TOP_SPACING, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, proxyHostLabel, TOP_SPACING, SpringLayout.SOUTH, servernameTextField); - serverLayout.putConstraint(SpringLayout.WEST, proxyHostLabel, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, proxyHostLabel, LEFT_ALIGNED, SpringLayout.WEST, servernameTextField); - serverLayout.putConstraint(SpringLayout.NORTH, proxyHostNameTextField, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, proxyHostNameTextField, TOP_ALIGNED, SpringLayout.SOUTH, proxyHostLabel); - serverLayout.putConstraint(SpringLayout.WEST, proxyHostNameTextField, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, proxyHostNameTextField, LEFT_ALIGNED, SpringLayout.WEST, proxyHostLabel); - serverLayout.putConstraint(SpringLayout.EAST, proxyHostNameTextField, RIGHT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.EAST, proxyHostNameTextField, RIGHT_ALIGNED, SpringLayout.EAST, servernameTextField); - serverLayout.putConstraint(SpringLayout.NORTH, proxyPortLabel, TOP_ALIGNED, SpringLayout.NORTH, proxyHostLabel); - serverLayout.putConstraint(SpringLayout.WEST, proxyPortLabel, LEFT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.NORTH, proxyPortLabel, TOP_ALIGNED, SpringLayout.NORTH, proxyHostLabel); + connectionLayout.putConstraint(SpringLayout.WEST, proxyPortLabel, LEFT_ALIGNED, SpringLayout.EAST, proxyHostNameTextField); - serverLayout.putConstraint(SpringLayout.NORTH, proxyPortTextField, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, proxyPortTextField, TOP_ALIGNED, SpringLayout.SOUTH, proxyPortLabel); - serverLayout.putConstraint(SpringLayout.WEST, proxyPortTextField, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, proxyPortTextField, LEFT_ALIGNED, SpringLayout.WEST, proxyPortLabel); - serverLayout.putConstraint(SpringLayout.EAST, proxyPortTextField, RIGHT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.EAST, proxyPortTextField, RIGHT_ALIGNED, SpringLayout.EAST, serverPortTextField); - serverLayout.putConstraint(SpringLayout.NORTH, serverUseProxyLabel, TOP_ALIGNED, SpringLayout.NORTH, + connectionLayout.putConstraint(SpringLayout.NORTH, serverUseProxyLabel, TOP_ALIGNED, SpringLayout.NORTH, proxyPortLabel); - serverLayout.putConstraint(SpringLayout.WEST, serverUseProxyLabel, LEFT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.WEST, serverUseProxyLabel, LEFT_ALIGNED, SpringLayout.EAST, proxyPortTextField); - serverLayout.putConstraint(SpringLayout.NORTH, serverProxyCheckBox, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, serverProxyCheckBox, TOP_ALIGNED, SpringLayout.SOUTH, serverUseProxyLabel); - serverLayout.putConstraint(SpringLayout.WEST, serverProxyCheckBox, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, serverProxyCheckBox, LEFT_ALIGNED, SpringLayout.WEST, serverUseProxyLabel); // Channel Stuff - serverLayout.putConstraint(SpringLayout.NORTH, firstChannelLabel, TOP_SPACING, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, firstChannelLabel, TOP_SPACING, SpringLayout.SOUTH, proxyHostNameTextField); - serverLayout.putConstraint(SpringLayout.WEST, firstChannelLabel, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, firstChannelLabel, LEFT_ALIGNED, SpringLayout.WEST, proxyHostNameTextField); - serverLayout.putConstraint(SpringLayout.NORTH, firstChannelTextField, TOP_ALIGNED, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, firstChannelTextField, TOP_ALIGNED, SpringLayout.SOUTH, firstChannelLabel); - serverLayout.putConstraint(SpringLayout.WEST, firstChannelTextField, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, firstChannelTextField, LEFT_ALIGNED, SpringLayout.WEST, firstChannelLabel); - serverLayout.putConstraint(SpringLayout.EAST, firstChannelTextField, RIGHT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.EAST, firstChannelTextField, RIGHT_ALIGNED, SpringLayout.EAST, proxyHostNameTextField); - serverLayout.putConstraint(SpringLayout.NORTH, connectButton, TOP_SPACING * TOP_SPACING, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, connectButton, TOP_SPACING * TOP_SPACING, SpringLayout.SOUTH, firstChannelTextField); - serverLayout.putConstraint(SpringLayout.WEST, connectButton, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, connectButton, LEFT_ALIGNED, SpringLayout.WEST, firstChannelTextField); - serverLayout.putConstraint(SpringLayout.NORTH, autoConnectToFavourites, TOP_ALIGNED, SpringLayout.NORTH, + connectionLayout.putConstraint(SpringLayout.NORTH, autoConnectToFavourites, TOP_ALIGNED, SpringLayout.NORTH, userNameLabel); - serverLayout.putConstraint(SpringLayout.WEST, autoConnectToFavourites, LEFT_SPACING, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.WEST, autoConnectToFavourites, LEFT_SPACING, SpringLayout.EAST, serverUseProxyLabel); - serverLayout.putConstraint(SpringLayout.NORTH, favouritesScroller, TOP_SPACING, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.NORTH, favouritesScroller, TOP_SPACING, SpringLayout.SOUTH, autoConnectToFavourites); - serverLayout.putConstraint(SpringLayout.WEST, favouritesScroller, LEFT_ALIGNED, SpringLayout.WEST, + connectionLayout.putConstraint(SpringLayout.WEST, favouritesScroller, LEFT_ALIGNED, SpringLayout.WEST, autoConnectToFavourites); - serverLayout.putConstraint(SpringLayout.EAST, favouritesScroller, LEFT_ALIGNED, SpringLayout.EAST, + connectionLayout.putConstraint(SpringLayout.EAST, favouritesScroller, LEFT_ALIGNED, SpringLayout.EAST, autoConnectToFavourites); - serverLayout.putConstraint(SpringLayout.SOUTH, favouritesScroller, TOP_SPACING, SpringLayout.SOUTH, + connectionLayout.putConstraint(SpringLayout.SOUTH, favouritesScroller, TOP_SPACING, SpringLayout.SOUTH, connectButton); } - private void setupClientOptionsPanelComponents() + private void setupAppearancePanel() { - - // clientScroller.setPreferredSize(new Dimension(this.getSize())); - // clientScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - // Settings for these are loaded with the settings API - // found in getClientSettings() - optionsClientPanel.add(lafOptionsLabel); - optionsClientPanel.add(lafOptions); + appearancePanel.add(lafOptionsLabel); + appearancePanel.add(lafOptions); // Set a custom renderer to display the look and feel names lafOptions.setRenderer(new DefaultListCellRenderer() { @@ -777,24 +775,65 @@ public Component getListCellRendererComponent(JList list, Object value, int i lafOptions.addActionListener(new ChangeLAFListener()); - optionsClientPanel.add(showEventTicker); - optionsClientPanel.add(showUsersList); - optionsClientPanel.add(enableClickableLinks); - optionsClientPanel.add(showJoinsQuitsEventTicker); - optionsClientPanel.add(showJoinsQuitsMainWindow); - optionsClientPanel.add(logChannelText); - optionsClientPanel.add(logServerActivity); - optionsClientPanel.add(logClientText); - optionsClientPanel.add(limitServerLines); - optionsClientPanel.add(limitServerLinesCount); - optionsClientPanel.add(limitChannelLines); - optionsClientPanel.add(limitChannelLinesCount); - optionsClientPanel.add(enableTimeStamps); - clientFontPanel = new FontPanel(getFont(), getProfilePath()); clientFontPanel.setPreferredSize(new Dimension(500, 48)); clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); - optionsClientPanel.add(clientFontPanel); + appearancePanel.add(clientFontPanel); + + setupAppearanceLayout(); + } + + private void setupAppearanceLayout() + { + SpringLayout appearanceLayout = new SpringLayout(); + appearancePanel.setLayout(appearanceLayout); + + // Used to make it more obvious what is going on - + // and perhaps more readable. + // 0 means THAT edge will be flush with the opposing components edge + // Yes, negative numbers will make it overlap + final int TOP_SPACING = 6; + final int TOP_ALIGNED = 0; + final int LEFT_ALIGNED = 0; + final int LEFT_SPACING = 6; + + + appearanceLayout.putConstraint(SpringLayout.WEST, lafOptionsLabel, LEFT_SPACING * 2, SpringLayout.WEST, appearancePanel); + + appearanceLayout.putConstraint(SpringLayout.WEST, lafOptions, LEFT_SPACING, SpringLayout.EAST, lafOptionsLabel); + appearanceLayout.putConstraint(SpringLayout.NORTH, lafOptions, TOP_SPACING * 2, SpringLayout.NORTH, appearancePanel); + + int centeredLabelPosition= (int) ((int) (lafOptions.getPreferredSize().getHeight() / 2) - (lafOptions.getPreferredSize().getHeight() - lafOptionsLabel.getPreferredSize().getHeight())); + + appearanceLayout.putConstraint(SpringLayout.NORTH, lafOptionsLabel, centeredLabelPosition, SpringLayout.NORTH, lafOptions); + + appearanceLayout.putConstraint(SpringLayout.NORTH, clientFontPanel, TOP_SPACING, SpringLayout.SOUTH, + lafOptionsLabel); + appearanceLayout.putConstraint(SpringLayout.WEST, clientFontPanel, LEFT_ALIGNED, SpringLayout.WEST, + lafOptionsLabel); + } + + private void setupInterfacePanel() + { + + // clientScroller.setPreferredSize(new Dimension(this.getSize())); + // clientScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + // Settings for these are loaded with the settings API + // found in getClientSettings() + + interfacePanel.add(showEventTicker); + interfacePanel.add(showUsersList); + interfacePanel.add(enableClickableLinks); + interfacePanel.add(showJoinsQuitsEventTicker); + interfacePanel.add(showJoinsQuitsMainWindow); + interfacePanel.add(logChannelText); + interfacePanel.add(logServerActivity); + interfacePanel.add(logClientText); + interfacePanel.add(limitServerLines); + interfacePanel.add(limitServerLinesCount); + interfacePanel.add(limitChannelLines); + interfacePanel.add(limitChannelLinesCount); + interfacePanel.add(enableTimeStamps); // Turn on labels at major tick mark. eventTickerDelay.setMajorTickSpacing(10); @@ -806,20 +845,19 @@ public Component getListCellRendererComponent(JList list, Object value, int i eventTickerDelay.setToolTipText("Event Ticker movement delay (Lower is faster)"); - optionsClientPanel.add(eventTickerLabel); - optionsClientPanel.add(eventTickerDelay); + interfacePanel.add(eventTickerLabel); + interfacePanel.add(eventTickerDelay); - setupClientOptionsLayout(); - // optionsRightPanel.add(optionsClientPanel, "Client"); + setupInterfaceLayout(); } /** * Aligns components on the Client Options Panel */ - private void setupClientOptionsLayout() + private void setupInterfaceLayout() { - SpringLayout clientLayout = new SpringLayout(); - optionsClientPanel.setLayout(clientLayout); + SpringLayout interfaceLayout = new SpringLayout(); + interfacePanel.setLayout(interfaceLayout); // Used to make it more obvious what is going on - // and perhaps more readable. @@ -832,90 +870,75 @@ private void setupClientOptionsLayout() // Components are aligned off the top label - clientLayout.putConstraint(SpringLayout.WEST, lafOptionsLabel, LEFT_SPACING, SpringLayout.WEST, optionsClientPanel); - - clientLayout.putConstraint(SpringLayout.WEST, lafOptions, LEFT_SPACING, SpringLayout.EAST, lafOptionsLabel); - clientLayout.putConstraint(SpringLayout.NORTH, lafOptions, TOP_SPACING * 2, SpringLayout.NORTH, optionsClientPanel); - - int centeredLabelPosition= (int) ((int) (lafOptions.getPreferredSize().getHeight() / 2) - (lafOptions.getPreferredSize().getHeight() - lafOptionsLabel.getPreferredSize().getHeight())); + interfaceLayout.putConstraint(SpringLayout.WEST, showEventTicker, LEFT_SPACING * 2, SpringLayout.WEST, interfacePanel); + interfaceLayout.putConstraint(SpringLayout.NORTH, showEventTicker, TOP_SPACING * 2, SpringLayout.NORTH, interfacePanel); - clientLayout.putConstraint(SpringLayout.NORTH, lafOptionsLabel, centeredLabelPosition, SpringLayout.NORTH, lafOptions); + interfaceLayout.putConstraint(SpringLayout.NORTH, showUsersList, TOP_SPACING, SpringLayout.SOUTH, showEventTicker); + interfaceLayout.putConstraint(SpringLayout.WEST, showUsersList, LEFT_ALIGNED, SpringLayout.WEST, showEventTicker); - clientLayout.putConstraint(SpringLayout.WEST, showEventTicker, LEFT_ALIGNED, SpringLayout.WEST, lafOptionsLabel); - clientLayout.putConstraint(SpringLayout.NORTH, showEventTicker, TOP_SPACING, SpringLayout.SOUTH, lafOptions); - - clientLayout.putConstraint(SpringLayout.NORTH, showUsersList, TOP_SPACING, SpringLayout.SOUTH, showEventTicker); - clientLayout.putConstraint(SpringLayout.WEST, showUsersList, LEFT_ALIGNED, SpringLayout.WEST, showEventTicker); - - clientLayout.putConstraint(SpringLayout.NORTH, enableClickableLinks, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, enableClickableLinks, TOP_SPACING, SpringLayout.SOUTH, showUsersList); - clientLayout.putConstraint(SpringLayout.WEST, enableClickableLinks, LEFT_ALIGNED, SpringLayout.WEST, + interfaceLayout.putConstraint(SpringLayout.WEST, enableClickableLinks, LEFT_ALIGNED, SpringLayout.WEST, showUsersList); - clientLayout.putConstraint(SpringLayout.NORTH, showJoinsQuitsEventTicker, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, showJoinsQuitsEventTicker, TOP_SPACING, SpringLayout.SOUTH, enableClickableLinks); - clientLayout.putConstraint(SpringLayout.WEST, showJoinsQuitsEventTicker, LEFT_ALIGNED, SpringLayout.WEST, + interfaceLayout.putConstraint(SpringLayout.WEST, showJoinsQuitsEventTicker, LEFT_ALIGNED, SpringLayout.WEST, enableClickableLinks); - clientLayout.putConstraint(SpringLayout.NORTH, showJoinsQuitsMainWindow, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, showJoinsQuitsMainWindow, TOP_SPACING, SpringLayout.SOUTH, showJoinsQuitsEventTicker); - clientLayout.putConstraint(SpringLayout.WEST, showJoinsQuitsMainWindow, LEFT_ALIGNED, SpringLayout.WEST, + interfaceLayout.putConstraint(SpringLayout.WEST, showJoinsQuitsMainWindow, LEFT_ALIGNED, SpringLayout.WEST, showJoinsQuitsEventTicker); - clientLayout.putConstraint(SpringLayout.NORTH, logChannelText, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, logChannelText, TOP_SPACING, SpringLayout.SOUTH, showJoinsQuitsMainWindow); - clientLayout.putConstraint(SpringLayout.WEST, logChannelText, LEFT_ALIGNED, SpringLayout.WEST, + interfaceLayout.putConstraint(SpringLayout.WEST, logChannelText, LEFT_ALIGNED, SpringLayout.WEST, showJoinsQuitsMainWindow); - clientLayout.putConstraint(SpringLayout.NORTH, logServerActivity, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, logServerActivity, TOP_SPACING, SpringLayout.SOUTH, logChannelText); - clientLayout.putConstraint(SpringLayout.WEST, logServerActivity, LEFT_ALIGNED, SpringLayout.WEST, + interfaceLayout.putConstraint(SpringLayout.WEST, logServerActivity, LEFT_ALIGNED, SpringLayout.WEST, logChannelText); - clientLayout.putConstraint(SpringLayout.NORTH, logClientText, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, logClientText, TOP_SPACING, SpringLayout.SOUTH, logServerActivity); - clientLayout.putConstraint(SpringLayout.WEST, logClientText, LEFT_ALIGNED, SpringLayout.WEST, + interfaceLayout.putConstraint(SpringLayout.WEST, logClientText, LEFT_ALIGNED, SpringLayout.WEST, logServerActivity); - clientLayout.putConstraint(SpringLayout.NORTH, limitServerLines, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, limitServerLines, TOP_SPACING, SpringLayout.SOUTH, logClientText); - clientLayout.putConstraint(SpringLayout.WEST, limitServerLines, LEFT_ALIGNED, SpringLayout.WEST, logClientText); + interfaceLayout.putConstraint(SpringLayout.WEST, limitServerLines, LEFT_ALIGNED, SpringLayout.WEST, logClientText); - clientLayout.putConstraint(SpringLayout.NORTH, limitServerLinesCount, TOP_ALIGNED, SpringLayout.NORTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, limitServerLinesCount, TOP_ALIGNED, SpringLayout.NORTH, limitServerLines); - clientLayout.putConstraint(SpringLayout.WEST, limitServerLinesCount, TOP_SPACING, SpringLayout.EAST, + interfaceLayout.putConstraint(SpringLayout.WEST, limitServerLinesCount, TOP_SPACING, SpringLayout.EAST, limitServerLines); - clientLayout.putConstraint(SpringLayout.NORTH, limitChannelLines, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, limitChannelLines, TOP_SPACING, SpringLayout.SOUTH, limitServerLines); - clientLayout.putConstraint(SpringLayout.WEST, limitChannelLines, LEFT_ALIGNED, SpringLayout.WEST, + interfaceLayout.putConstraint(SpringLayout.WEST, limitChannelLines, LEFT_ALIGNED, SpringLayout.WEST, limitServerLines); - clientLayout.putConstraint(SpringLayout.NORTH, limitChannelLinesCount, TOP_ALIGNED, SpringLayout.NORTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, limitChannelLinesCount, TOP_ALIGNED, SpringLayout.NORTH, limitChannelLines); - clientLayout.putConstraint(SpringLayout.WEST, limitChannelLinesCount, LEFT_SPACING, SpringLayout.EAST, + interfaceLayout.putConstraint(SpringLayout.WEST, limitChannelLinesCount, LEFT_SPACING, SpringLayout.EAST, limitChannelLines); - clientLayout.putConstraint(SpringLayout.NORTH, enableTimeStamps, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, enableTimeStamps, TOP_SPACING, SpringLayout.SOUTH, limitChannelLines); - clientLayout.putConstraint(SpringLayout.WEST, enableTimeStamps, LEFT_ALIGNED, SpringLayout.WEST, + interfaceLayout.putConstraint(SpringLayout.WEST, enableTimeStamps, LEFT_ALIGNED, SpringLayout.WEST, limitChannelLines); - clientLayout.putConstraint(SpringLayout.NORTH, clientFontPanel, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, eventTickerLabel, TOP_SPACING, SpringLayout.SOUTH, enableTimeStamps); - clientLayout.putConstraint(SpringLayout.WEST, clientFontPanel, LEFT_SPACING, SpringLayout.WEST, + interfaceLayout.putConstraint(SpringLayout.WEST, eventTickerLabel, LEFT_ALIGNED, SpringLayout.WEST, enableTimeStamps); - - clientLayout.putConstraint(SpringLayout.NORTH, eventTickerLabel, TOP_SPACING, SpringLayout.SOUTH, - clientFontPanel); - clientLayout.putConstraint(SpringLayout.WEST, eventTickerLabel, LEFT_ALIGNED, SpringLayout.WEST, - clientFontPanel); - - clientLayout.putConstraint(SpringLayout.NORTH, eventTickerDelay, TOP_SPACING, SpringLayout.SOUTH, + interfaceLayout.putConstraint(SpringLayout.NORTH, eventTickerDelay, TOP_SPACING, SpringLayout.SOUTH, eventTickerLabel); - clientLayout.putConstraint(SpringLayout.WEST, eventTickerDelay, LEFT_ALIGNED, SpringLayout.WEST, + interfaceLayout.putConstraint(SpringLayout.WEST, eventTickerDelay, LEFT_ALIGNED, SpringLayout.WEST, eventTickerLabel); } @@ -1805,7 +1828,7 @@ public void run() // Auto-generated method stub Thread.currentThread().setContextClassLoader(DriverGUI.contextClassLoader); Thread.currentThread().setUncaughtExceptionHandler(new URUncaughtExceptionHandler()); - + setNewLAF(((LookAndFeelInfo) lafOptions.getSelectedItem()).getClassName()); } } diff --git a/src/urChatBasic/frontend/components/ProfilePicker.java b/src/urChatBasic/frontend/components/ProfilePicker.java index 2d4d1c6..605fb31 100644 --- a/src/urChatBasic/frontend/components/ProfilePicker.java +++ b/src/urChatBasic/frontend/components/ProfilePicker.java @@ -45,11 +45,18 @@ public void actionPerformed(ActionEvent e) String selectedString = profileComboBox.getSelectedItem().toString(); if (DriverGUI.gui.getProfileName() != selectedString && !selectedString.isBlank()) { + //TODO Show dialog to either rename the existing profile, or create a new profile + String currentProfile = DriverGUI.gui.getProfileName(); + DriverGUI.gui.setProfileName(selectedString); if (!profileExists(selectedString)) { + // If create new profile selected profileComboBox.addItem(selectedString); + + // If rename existing profile selected... + // TODO } } else if (selectedString.isBlank()) { From 794b6dd942a85a022fdc392f1a86d6591a369b36 Mon Sep 17 00:00:00 2001 From: matty_r Date: Thu, 26 Oct 2023 06:25:58 +1000 Subject: [PATCH 21/78] Adjustments to the font panel --- src/urChatBasic/frontend/UserGUI.java | 4 +- .../frontend/components/FontPanel.java | 51 ++++++++++++++----- .../frontend/dialogs/FontDialog.java | 2 +- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 0c18dfb..0238813 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -775,8 +775,8 @@ public Component getListCellRendererComponent(JList list, Object value, int i lafOptions.addActionListener(new ChangeLAFListener()); - clientFontPanel = new FontPanel(getFont(), getProfilePath()); - clientFontPanel.setPreferredSize(new Dimension(500, 48)); + clientFontPanel = new FontPanel(getFont(), getProfilePath(), "Global Font:"); + clientFontPanel.setPreferredSize(new Dimension(500, 64)); clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); appearancePanel.add(clientFontPanel); diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 4270349..aba894b 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -3,6 +3,8 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.GraphicsEnvironment; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -17,7 +19,7 @@ public class FontPanel extends JPanel /** * */ - private static final long serialVersionUID = 4044242988594083226L; + // private static final long serialVersionUID = 4044242988594083226L; private final JLabel TEXT_PREVIEW = new JLabel("A quick brown fox 0123456789"); private final String[] FONT_LIST = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); private final JComboBox FONT_COMBO_BOX = new JComboBox(FONT_LIST); @@ -26,34 +28,59 @@ public class FontPanel extends JPanel private final JCheckBox MAKE_BOLD = new JCheckBox("BOLD"); private final JCheckBox MAKE_ITALIC = new JCheckBox("ITALIC"); private final JButton SAVE_BUTTON = new JButton("Save Font"); + // private String fontType = "New Font:"; + private JLabel fontTypeLabel = new JLabel("New Font:"); + private final JPanel TITLE_PANEL = new JPanel(new GridLayout(1,1)); + private final JPanel MAIN_PANEL = new JPanel(new GridLayout(2, 3)); private Font defaultFont; // private final JButton CANCEL_BUTTON = new JButton("Cancel"); private Preferences settingsPath; - public FontPanel(Font defaultFont, Preferences settingsPath) + public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) { - setPreferredSize(new Dimension(0, 50)); - setLayout(new GridLayout(2, 6)); + // setPreferredSize(new Dimension(0, 100)); + fontTypeLabel = new JLabel(fontName); + setLayout(new GridBagLayout()); + + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + + c.gridx = 0; + c.gridy = 0; + + TITLE_PANEL.add(fontTypeLabel); + add(TITLE_PANEL, c); setSettingsPath(settingsPath); setDefaultFont(defaultFont); loadFont(); - add(FONT_COMBO_BOX); - add(SIZES_COMBO_BOX); - add(MAKE_BOLD); - add(MAKE_ITALIC); - add(TEXT_PREVIEW); - add(SAVE_BUTTON); - - + MAIN_PANEL.add(FONT_COMBO_BOX); + MAIN_PANEL.add(SIZES_COMBO_BOX); + MAIN_PANEL.add(MAKE_BOLD); + MAIN_PANEL.add(MAKE_ITALIC); + MAIN_PANEL.add(TEXT_PREVIEW); + MAIN_PANEL.add(SAVE_BUTTON); SAVE_BUTTON.addActionListener(new SaveListener()); FONT_COMBO_BOX.addItemListener(new FontSelectionChange()); SIZES_COMBO_BOX.addItemListener(new FontSelectionChange()); MAKE_BOLD.addActionListener(new CheckListener()); MAKE_ITALIC.addActionListener(new CheckListener()); + + // Reset the GridBagConstraints for MAIN_PANEL + c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.gridx = 0; + c.gridy = 1; + + // Set constraints for MAIN_PANEL + c.gridwidth = 1; // Assuming you want MAIN_PANEL to span two columns + c.weightx = 1.0; + c.weighty = 1.0; + + add(MAIN_PANEL, c); } public JButton getSaveButton() diff --git a/src/urChatBasic/frontend/dialogs/FontDialog.java b/src/urChatBasic/frontend/dialogs/FontDialog.java index 8f22246..776d177 100644 --- a/src/urChatBasic/frontend/dialogs/FontDialog.java +++ b/src/urChatBasic/frontend/dialogs/FontDialog.java @@ -25,7 +25,7 @@ public void initFontDialog(Font defaultFont, Preferences settingsPath) setMaximumSize(new Dimension(600, 100)); setLocationRelativeTo(super.getParent()); - fontPanel = new FontPanel(defaultFont, settingsPath); + fontPanel = new FontPanel(defaultFont, settingsPath, "Default Font:"); add(fontPanel); } From c15ffbb2dbe6749820d320211b3f87a558f01ab6 Mon Sep 17 00:00:00 2001 From: matty_r Date: Sun, 29 Oct 2023 07:24:11 +1000 Subject: [PATCH 22/78] Introducing a way to add components to the panels easier --- src/urChatBasic/base/Constants.java | 10 ++- src/urChatBasic/frontend/LineFormatter.java | 3 + src/urChatBasic/frontend/UserGUI.java | 87 ++++++++++--------- .../frontend/components/FontPanel.java | 3 +- .../frontend/components/URComponent.java | 65 ++++++++++++++ 5 files changed, 123 insertions(+), 45 deletions(-) create mode 100644 src/urChatBasic/frontend/components/URComponent.java diff --git a/src/urChatBasic/base/Constants.java b/src/urChatBasic/base/Constants.java index ab2d378..be34965 100644 --- a/src/urChatBasic/base/Constants.java +++ b/src/urChatBasic/base/Constants.java @@ -91,6 +91,7 @@ public class Constants public static final String DEFAULT_NICK_NAME = "urChatClient"; public static final String DEFAULT_REAL_NAME = "urChatClient"; public static final Boolean DEFAULT_TIME_STAMPS = true; + public static final String DEFAULT_TIME_STAMP_FORMAT = "HHmm"; public static final String DEFAULT_LAF_NAME = UIManager.getSystemLookAndFeelClassName(); public static final Boolean DEFAULT_EVENT_TICKER_ACTIVE = true; public static final Boolean DEFAULT_CLICKABLE_LINKS_ENABLED = true; @@ -129,10 +130,15 @@ public class Constants public static final int MAIN_WIDTH = 500; public static final int MAIN_HEIGHT = 400; + public enum Size { + LARGE, + MEDIUM, + SMALL, + NONE + } + /** * Used to initialize some values that may throw exceptions. - * - * @author goofybud16 */ public static void init() { diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 701c281..bda4c1f 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -367,6 +367,9 @@ private String parseClickableText(StyledDocument doc, IRCUser fromUser) throws B int styleStart = relativePosition + matcher.start(); int styleLength = matcher.end() - matcher.start(); + linkStyle.addAttribute("startStyle", styleStart); + linkStyle.addAttribute("styleLength", styleLength); + doc.setCharacterAttributes(styleStart, styleLength, linkStyle, true); } } diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 0238813..4fb756b 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -19,6 +19,7 @@ import urChatBasic.frontend.dialogs.FontDialog; import urChatBasic.frontend.dialogs.MessageDialog; import urChatBasic.base.UserGUIBase; +import urChatBasic.base.Constants.Size; import urChatBasic.base.capabilities.CapTypeBase; import urChatBasic.base.capabilities.CapabilityTypes; import urChatBasic.frontend.components.*; @@ -52,9 +53,10 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase // Client Options Panel private static final JPanel interfacePanel = new JPanel(); private static final JScrollPane interfaceScroller = new JScrollPane(interfacePanel); - private static final JLabel lafOptionsLabel = new JLabel("Theme:"); private static final JComboBox lafOptions = new JComboBox(UIManager.getInstalledLookAndFeels()); + private static final URComponent lafOptionsComponent = new URComponent("Theme:", lafOptions, Size.LARGE); + private static final JCheckBox showEventTicker = new JCheckBox("Show Event Ticker"); private static final JCheckBox showUsersList = new JCheckBox("Show Users List"); private static final JCheckBox enableClickableLinks = new JCheckBox("Make links clickable"); @@ -66,7 +68,11 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase private static final JCheckBox limitServerLines = new JCheckBox("Limit the number of lines in Server activity"); private static final JCheckBox limitChannelLines = new JCheckBox("Limit the number of lines in channel text"); private static final JCheckBox enableTimeStamps = new JCheckBox("Time Stamp chat messages"); + + // Appearance Panel private FontPanel clientFontPanel; + private static final JTextField timeStampFormat = new JTextField(Constants.DEFAULT_TIME_STAMP_FORMAT); + private static final URComponent timeStampComponent = new URComponent("Timestamp Format:", timeStampFormat, Size.MEDIUM); private static final JTextField limitServerLinesCount = new JTextField(); private static final JTextField limitChannelLinesCount = new JTextField(); @@ -510,6 +516,42 @@ private void setupRightOptionsPanel() setupAppearancePanel(); } + private static void addToPanel(JPanel targetPanel, Component newComponent) + { + + final int TOP_SPACING = 6; + final int TOP_ALIGNED = 0; + final int LEFT_ALIGNED = 0; + final int LEFT_SPACING = 6; + + if(targetPanel.getLayout().getClass() != SpringLayout.class) + { + targetPanel.setLayout(new SpringLayout()); + } + + SpringLayout layout = (SpringLayout) targetPanel.getLayout(); + Component[] components = targetPanel.getComponents(); + + if (components.length > 0) { + Component previousComponent = components[components.length - 1]; + + // Add newComponent to the targetPanel + targetPanel.add(newComponent); + + // Set constraints for newComponent + layout.putConstraint(SpringLayout.NORTH, newComponent, TOP_SPACING, SpringLayout.SOUTH, previousComponent); + layout.putConstraint(SpringLayout.WEST, newComponent, LEFT_ALIGNED, SpringLayout.WEST, previousComponent); + } else { + // If it's the first component, align it against the targetPanel + targetPanel.add(newComponent); + + // Set constraints for newComponent when it's the first component + layout.putConstraint(SpringLayout.NORTH, newComponent, TOP_SPACING * 2, SpringLayout.NORTH, targetPanel); + layout.putConstraint(SpringLayout.WEST, newComponent, LEFT_SPACING * 2, SpringLayout.WEST, targetPanel); + } + } + + /** * Add the components to the Server Options Panel. */ @@ -761,8 +803,7 @@ private void setupConnectionLayout() private void setupAppearancePanel() { - appearancePanel.add(lafOptionsLabel); - appearancePanel.add(lafOptions); + addToPanel(appearancePanel, lafOptionsComponent); // Set a custom renderer to display the look and feel names lafOptions.setRenderer(new DefaultListCellRenderer() { @@ -778,49 +819,13 @@ public Component getListCellRendererComponent(JList list, Object value, int i clientFontPanel = new FontPanel(getFont(), getProfilePath(), "Global Font:"); clientFontPanel.setPreferredSize(new Dimension(500, 64)); clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); - appearancePanel.add(clientFontPanel); - setupAppearanceLayout(); - } - - private void setupAppearanceLayout() - { - SpringLayout appearanceLayout = new SpringLayout(); - appearancePanel.setLayout(appearanceLayout); - - // Used to make it more obvious what is going on - - // and perhaps more readable. - // 0 means THAT edge will be flush with the opposing components edge - // Yes, negative numbers will make it overlap - final int TOP_SPACING = 6; - final int TOP_ALIGNED = 0; - final int LEFT_ALIGNED = 0; - final int LEFT_SPACING = 6; - - - appearanceLayout.putConstraint(SpringLayout.WEST, lafOptionsLabel, LEFT_SPACING * 2, SpringLayout.WEST, appearancePanel); - - appearanceLayout.putConstraint(SpringLayout.WEST, lafOptions, LEFT_SPACING, SpringLayout.EAST, lafOptionsLabel); - appearanceLayout.putConstraint(SpringLayout.NORTH, lafOptions, TOP_SPACING * 2, SpringLayout.NORTH, appearancePanel); - - int centeredLabelPosition= (int) ((int) (lafOptions.getPreferredSize().getHeight() / 2) - (lafOptions.getPreferredSize().getHeight() - lafOptionsLabel.getPreferredSize().getHeight())); - - appearanceLayout.putConstraint(SpringLayout.NORTH, lafOptionsLabel, centeredLabelPosition, SpringLayout.NORTH, lafOptions); - - appearanceLayout.putConstraint(SpringLayout.NORTH, clientFontPanel, TOP_SPACING, SpringLayout.SOUTH, - lafOptionsLabel); - appearanceLayout.putConstraint(SpringLayout.WEST, clientFontPanel, LEFT_ALIGNED, SpringLayout.WEST, - lafOptionsLabel); + addToPanel(appearancePanel, clientFontPanel); + addToPanel(appearancePanel, timeStampComponent); } private void setupInterfacePanel() { - - // clientScroller.setPreferredSize(new Dimension(this.getSize())); - // clientScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - // Settings for these are loaded with the settings API - // found in getClientSettings() - interfacePanel.add(showEventTicker); interfacePanel.add(showUsersList); interfacePanel.add(enableClickableLinks); diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index aba894b..f4f91d4 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -1,6 +1,5 @@ package urChatBasic.frontend.components; -import java.awt.Dimension; import java.awt.Font; import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; @@ -58,9 +57,9 @@ public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) MAIN_PANEL.add(FONT_COMBO_BOX); MAIN_PANEL.add(SIZES_COMBO_BOX); + MAIN_PANEL.add(TEXT_PREVIEW); MAIN_PANEL.add(MAKE_BOLD); MAIN_PANEL.add(MAKE_ITALIC); - MAIN_PANEL.add(TEXT_PREVIEW); MAIN_PANEL.add(SAVE_BUTTON); SAVE_BUTTON.addActionListener(new SaveListener()); diff --git a/src/urChatBasic/frontend/components/URComponent.java b/src/urChatBasic/frontend/components/URComponent.java new file mode 100644 index 0000000..c532b78 --- /dev/null +++ b/src/urChatBasic/frontend/components/URComponent.java @@ -0,0 +1,65 @@ +package urChatBasic.frontend.components; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; + +import javax.swing.BoxLayout; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import urChatBasic.base.Constants.Size; + +public class URComponent extends JPanel { + private JLabel label; + private JComponent component; + private Size size; + + public URComponent(String labelText, JComponent component, Size size) { + this.label = new JLabel(labelText); + this.component = component; + this.size = size; + init(); + } + + private int convertSize() + { + switch (size) { + case LARGE: + return 240; + case MEDIUM: + return 160; + case SMALL: + return 80; + default: + return 60; + } + } + + private void init() { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + label.setAlignmentX( Component.LEFT_ALIGNMENT); + label.setPreferredSize( new Dimension(convertSize(), label.getPreferredSize().height)); + + component.setAlignmentX( Component.LEFT_ALIGNMENT); + component.setPreferredSize( new Dimension(convertSize(), component.getPreferredSize().height)); + add(label); + add(component); + } + + public JComponent getComponent() { + return component; + } + + public JTextField getAsTextField() + { + return (JTextField) getComponent(); + } + + public void setComponent(JComponent component) { + this.component = component; + } +} From 2668e662c11bc9e83afde40fb334d50ae17055f8 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 3 Nov 2023 16:40:58 +1000 Subject: [PATCH 23/78] Adding a formatting preview area --- src/urChatBasic/frontend/LineFormatter.java | 49 +++++++++++-- src/urChatBasic/frontend/UserGUI.java | 72 +++++++++++++++++-- .../frontend/components/FontPanel.java | 16 ++--- .../frontend/components/FontPreview.java | 17 +++++ .../frontend/dialogs/FontDialog.java | 11 +++ 5 files changed, 144 insertions(+), 21 deletions(-) create mode 100644 src/urChatBasic/frontend/components/FontPreview.java diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index bda4c1f..3997530 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -149,6 +149,11 @@ public SimpleAttributeSet myStyle() return tempStyle; } + public void setNick(String myNick) + { + this.myNick = myNick; + } + public class ClickableText extends AbstractAction { private String textLink; @@ -263,14 +268,33 @@ public void updateStyles(StyledDocument doc, int startPosition) SimpleAttributeSet matchingStyle = getStyle(styleName); + if(styleName.equalsIgnoreCase("urlStyle")) + { + System.out.println("sda"); + } + // Copy the attributes, but only if they aren't already set Iterator attributeIterator = textStyle.getAttributeNames().asIterator(); while(attributeIterator.hasNext()) { String nextAttributeName = attributeIterator.next().toString(); + + // get attribute "foreground" isn't working here despite foregrounf having been set if(matchingStyle.getAttribute(nextAttributeName) == null) { - matchingStyle.addAttribute(nextAttributeName, textStyle.getAttribute(nextAttributeName)); + Iterator matchingIterator = matchingStyle.getAttributeNames().asIterator(); + boolean needsToBeSet = true; + + while(matchingIterator.hasNext()) + { + if(matchingIterator.next().toString().equalsIgnoreCase(nextAttributeName)) + { + needsToBeSet = false; + break; + } + } + if(needsToBeSet) + matchingStyle.addAttribute(nextAttributeName, textStyle.getAttribute(nextAttributeName)); } } @@ -367,9 +391,20 @@ private String parseClickableText(StyledDocument doc, IRCUser fromUser) throws B int styleStart = relativePosition + matcher.start(); int styleLength = matcher.end() - matcher.start(); - linkStyle.addAttribute("startStyle", styleStart); + linkStyle.addAttribute("styleStart", styleStart); linkStyle.addAttribute("styleLength", styleLength); + // update the styleLength of the previous style + SimpleAttributeSet oldStyle = getStyleAtPosition(doc, styleStart - 1, ""); + SimpleAttributeSet replaceStyle = getStyle(oldStyle.getAttribute("name").toString()); + int newStart = Integer.parseInt(oldStyle.getAttribute("styleStart").toString()); + int newLength = styleStart - Integer.parseInt(oldStyle.getAttribute("styleStart").toString()) + 1; + replaceStyle.addAttribute("styleStart", newStart); + replaceStyle.addAttribute("styleLength", newLength); + replaceStyle.addAttribute("docLength", oldStyle.getAttribute("docLength")); + + doc.setCharacterAttributes(newStart, newLength, replaceStyle, true); + doc.setCharacterAttributes(styleStart, styleLength, linkStyle, true); } } @@ -412,8 +447,10 @@ public void formattedDocument(StyledDocument doc, String timeLine, IRCUser fromU { // doc.insertString(doc.getLength(), timeLine, timeStyle); - appendString(doc, timeLine, timeStyle); - appendString(doc, " <", lineStyle); + if(null != timeLine && !timeLine.isBlank()) + appendString(doc, timeLine + " ", timeStyle); + + appendString(doc, "<", lineStyle); if(fromUser != null) { @@ -427,10 +464,10 @@ public void formattedDocument(StyledDocument doc, String timeLine, IRCUser fromU appendString(doc, fromString, nameStyle); } - appendString(doc, "> ", lineStyle); + appendString(doc, ">", lineStyle); // print the remaining text - appendString(doc, line, lineStyle); + appendString(doc, " "+line, lineStyle); // parse the outputted line for clickable text parseClickableText(doc, fromUser); diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 4fb756b..5d05bdd 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -7,11 +7,15 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.*; import java.util.List; import javax.swing.*; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.event.*; +import javax.swing.text.StyledDocument; +import javax.swing.text.StyledEditorKit; import urChatBasic.backend.utils.URUncaughtExceptionHandler; import urChatBasic.base.Constants; import urChatBasic.base.IRCRoomBase; @@ -73,6 +77,16 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase private FontPanel clientFontPanel; private static final JTextField timeStampFormat = new JTextField(Constants.DEFAULT_TIME_STAMP_FORMAT); private static final URComponent timeStampComponent = new URComponent("Timestamp Format:", timeStampFormat, Size.MEDIUM); + private static final JLabel timeStampFontLabel = new JLabel("Timestamp Font"); + private static final JButton otherNickFontLabel = new JButton("Other Nick Font"); + private static final JButton userNickFontLabel = new JButton("My Nick Font"); + private static final JButton lowStyleFontLabel = new JButton("Low Priority Text Font"); + private static final JButton mediumStyleFontLabel = new JButton("Medium Priority Text Font"); + private static final JButton highStyleFontLabel = new JButton("High Priority Text Font"); + private static final JTextPane previewTextArea = new JTextPane(); + private static final JScrollPane previewTextScroll = new JScrollPane(previewTextArea); + private static LineFormatter previewLineFormatter; + private static final JTextField limitServerLinesCount = new JTextField(); private static final JTextField limitChannelLinesCount = new JTextField(); @@ -516,14 +530,21 @@ private void setupRightOptionsPanel() setupAppearancePanel(); } - private static void addToPanel(JPanel targetPanel, Component newComponent) + private static void addToPanel(JPanel targetPanel, Component newComponent, String label) { - final int TOP_SPACING = 6; + int topSpacing = 6; final int TOP_ALIGNED = 0; final int LEFT_ALIGNED = 0; final int LEFT_SPACING = 6; + if(null != label && !label.isBlank()) + { + addToPanel(targetPanel, new JLabel(label + ":"), null); + // There is a label, so we want the added component to be aligned with the label + topSpacing = 0; + } + if(targetPanel.getLayout().getClass() != SpringLayout.class) { targetPanel.setLayout(new SpringLayout()); @@ -539,14 +560,14 @@ private static void addToPanel(JPanel targetPanel, Component newComponent) targetPanel.add(newComponent); // Set constraints for newComponent - layout.putConstraint(SpringLayout.NORTH, newComponent, TOP_SPACING, SpringLayout.SOUTH, previousComponent); + layout.putConstraint(SpringLayout.NORTH, newComponent, topSpacing, SpringLayout.SOUTH, previousComponent); layout.putConstraint(SpringLayout.WEST, newComponent, LEFT_ALIGNED, SpringLayout.WEST, previousComponent); } else { // If it's the first component, align it against the targetPanel targetPanel.add(newComponent); // Set constraints for newComponent when it's the first component - layout.putConstraint(SpringLayout.NORTH, newComponent, TOP_SPACING * 2, SpringLayout.NORTH, targetPanel); + layout.putConstraint(SpringLayout.NORTH, newComponent, topSpacing * 2, SpringLayout.NORTH, targetPanel); layout.putConstraint(SpringLayout.WEST, newComponent, LEFT_SPACING * 2, SpringLayout.WEST, targetPanel); } } @@ -803,7 +824,7 @@ private void setupConnectionLayout() private void setupAppearancePanel() { - addToPanel(appearancePanel, lafOptionsComponent); + addToPanel(appearancePanel, lafOptionsComponent, null); // Set a custom renderer to display the look and feel names lafOptions.setRenderer(new DefaultListCellRenderer() { @@ -820,8 +841,41 @@ public Component getListCellRendererComponent(JList list, Object value, int i clientFontPanel.setPreferredSize(new Dimension(500, 64)); clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); - addToPanel(appearancePanel, clientFontPanel); - addToPanel(appearancePanel, timeStampComponent); + // FontDialog timeStampFontDialog = new FontDialog("Timestamp Font:", UserGUI.this.getFont(), getProfilePath()); + // timeStampFontLabel.setFont + + StyledDocument previewDoc = (StyledDocument) previewTextArea.getDocument(); + + previewTextScroll.setPreferredSize(new Dimension(500, 200)); + previewTextArea.setEditable(false); + // previewTextArea.setFont(clientFontPanel.getFont()); + previewLineFormatter = new LineFormatter(clientFontPanel.getFont(), null); + + previewTextArea.setCaretPosition(previewTextArea.getDocument().getLength()); + + DateFormat chatDateFormat = new SimpleDateFormat("HHmm"); + Date chatDate = new Date(); + String timeLine = "[" + chatDateFormat.format(chatDate) + "]"; + + + previewLineFormatter.setNick("urChatClient"); + previewLineFormatter.formattedDocument(previewDoc, timeLine, null, "matty_r", "Hello, world!"); + previewLineFormatter.formattedDocument(previewDoc, timeLine, null, "matty_r", "Hello, urChatClient!"); + previewLineFormatter.formattedDocument(previewDoc, timeLine, null, "urChatClient", "Go to https://github.com/matty-r/urChat"); + previewLineFormatter.formattedDocument(previewDoc, timeLine, null, "urChatClient", "Join #urchatclient on irc.libera.chat"); + + // private static final JLabel timeStampFontLabel = new JLabel("Timestamp Font"); + // private static final JButton otherNickFontLabel = new JButton("Other Nick Font"); + // private static final JButton userNickFontLabel = new JButton("My Nick Font"); + // private static final JButton lowStyleFontLabel = new JButton("Low Priority Text Font"); + // private static final JButton mediumStyleFontLabel = new JButton("Medium Priority Text Font"); + // private static final JButton highStyleFontLabel = new JButton("High Priority Text Font"); + + addToPanel(appearancePanel, clientFontPanel, "Global Font"); + addToPanel(appearancePanel, timeStampComponent, null); + + addToPanel(appearancePanel, previewTextScroll, "Font Preview"); + // addToPanel(appearancePanel, timeStampFontButton); } private void setupInterfacePanel() @@ -1813,6 +1867,7 @@ private void updateExtras() SwingUtilities.updateComponentTreeUI(((IRCRoomBase) tab).myMenu); SwingUtilities.updateComponentTreeUI(((IRCRoomBase) tab).getFontPanel()); } + } for (int index = 0; index < favouritesList.getModel().getSize(); index++) @@ -1820,6 +1875,9 @@ private void updateExtras() FavouritesItem favouriteItem = favouritesList.getModel().getElementAt(index); SwingUtilities.updateComponentTreeUI(favouriteItem.myMenu); } + + // update the styles in the preview text area + previewLineFormatter.updateStyles(previewTextArea.getStyledDocument(), 0); } /* diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index f4f91d4..9a5f0b3 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -28,8 +28,8 @@ public class FontPanel extends JPanel private final JCheckBox MAKE_ITALIC = new JCheckBox("ITALIC"); private final JButton SAVE_BUTTON = new JButton("Save Font"); // private String fontType = "New Font:"; - private JLabel fontTypeLabel = new JLabel("New Font:"); - private final JPanel TITLE_PANEL = new JPanel(new GridLayout(1,1)); + // private JLabel fontTypeLabel = new JLabel("New Font:"); + // private final JPanel TITLE_PANEL = new JPanel(new GridLayout(1,1)); private final JPanel MAIN_PANEL = new JPanel(new GridLayout(2, 3)); private Font defaultFont; // private final JButton CANCEL_BUTTON = new JButton("Cancel"); @@ -39,17 +39,17 @@ public class FontPanel extends JPanel public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) { // setPreferredSize(new Dimension(0, 100)); - fontTypeLabel = new JLabel(fontName); + // fontTypeLabel = new JLabel(fontName); setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.HORIZONTAL; + // c.fill = GridBagConstraints.HORIZONTAL; - c.gridx = 0; - c.gridy = 0; + // c.gridx = 0; + // c.gridy = 0; - TITLE_PANEL.add(fontTypeLabel); - add(TITLE_PANEL, c); + // TITLE_PANEL.add(fontTypeLabel); + // add(TITLE_PANEL, c); setSettingsPath(settingsPath); setDefaultFont(defaultFont); diff --git a/src/urChatBasic/frontend/components/FontPreview.java b/src/urChatBasic/frontend/components/FontPreview.java new file mode 100644 index 0000000..a5137c1 --- /dev/null +++ b/src/urChatBasic/frontend/components/FontPreview.java @@ -0,0 +1,17 @@ +package urChatBasic.frontend.components; + +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextPane; + +public class FontPreview extends JPanel { + + private JTextPane previewTextArea = new JTextPane(); + private JScrollPane previewScroll = new JScrollPane(previewTextArea); + + public FontPreview() + { + + } +} diff --git a/src/urChatBasic/frontend/dialogs/FontDialog.java b/src/urChatBasic/frontend/dialogs/FontDialog.java index 776d177..b373d9b 100644 --- a/src/urChatBasic/frontend/dialogs/FontDialog.java +++ b/src/urChatBasic/frontend/dialogs/FontDialog.java @@ -2,6 +2,7 @@ import java.awt.Dimension; import java.awt.Font; +import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.prefs.Preferences; import urChatBasic.base.DialogBase; @@ -46,4 +47,14 @@ public void addSaveListener(ActionListener newActionListener) { fontPanel.getSaveButton().addActionListener(newActionListener); } + + public class ShowFontDialog implements ActionListener + { + @Override + public void actionPerformed(ActionEvent arg0) + { + fontPanel.loadFont(); + FontDialog.this.setVisible(true); + } + } } From cabf77d84daeee68bbeb5f56286a92c082c3e392 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 4 Nov 2023 06:57:19 +1000 Subject: [PATCH 24/78] Adjust handling of channel regex, and capturing the matched string. Adjust handling of the timestamp in order to make it adjustable formatting. Improved the parseClickableText function to preserve formatting. --- src/urChatBasic/base/Constants.java | 2 +- src/urChatBasic/base/IRCRoomBase.java | 2 +- src/urChatBasic/frontend/LineFormatter.java | 101 ++++++++++++------ src/urChatBasic/frontend/UserGUI.java | 23 ++-- src/urChatBasic/frontend/utils/URColour.java | 2 +- .../tests/backend/MessageHandlerTests.java | 7 +- 6 files changed, 91 insertions(+), 46 deletions(-) diff --git a/src/urChatBasic/base/Constants.java b/src/urChatBasic/base/Constants.java index be34965..df48bca 100644 --- a/src/urChatBasic/base/Constants.java +++ b/src/urChatBasic/base/Constants.java @@ -121,7 +121,7 @@ public class Constants public static final String END_MESSAGE = "\r\n"; // We 'must' match against http(s) in order to define the correct protocol to be used public static final String URL_REGEX = "((http:\\/\\/|https:\\/\\/)(www.)?(([a-zA-Z0-9-]){2,}\\.){1,4}([a-zA-Z]){2,6}(\\/([a-zA-Z-_\\/\\.0-9#:?=&;,]*)?)?)"; - public static final String CHANNEL_REGEX = "#([^\s,]+)(?!,)"; + public static final String CHANNEL_REGEX = "(?:^|\s)(#([^\s,]+)(?!,))(?:$|\s)"; // Used to identify a message to be printed from the Event ticker // like a "user joins room" type message public static final String EVENT_USER = "****"; diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 5de0fe9..3fafd3f 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -526,7 +526,7 @@ public void run() if (fromUser.equals(Constants.EVENT_USER) || !fromIRCUser.isMuted()) { - lineFormatter.formattedDocument(doc, timeLine, fromIRCUser, fromUser, line); + lineFormatter.formattedDocument(doc, new Date(), fromIRCUser, fromUser, line); if (lineFormatter.nameStyle.getAttribute("name") == lineFormatter.highStyle() .getAttribute("name")) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 3997530..a09d701 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -5,6 +5,8 @@ import java.awt.Font; import java.awt.event.ActionEvent; import java.net.URL; +import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -85,7 +87,14 @@ public SimpleAttributeSet lowStyle() { SimpleAttributeSet tempStyle = defaultStyle(); tempStyle.addAttribute("name", "lowStyle"); - StyleConstants.setForeground(tempStyle, Color.LIGHT_GRAY); + + if(URColour.useDarkColour(UIManager.getColor("Panel.background"))) + { + StyleConstants.setForeground(tempStyle, Color.DARK_GRAY); + } else { + StyleConstants.setForeground(tempStyle, Color.LIGHT_GRAY); + } + return tempStyle; } @@ -171,6 +180,12 @@ public class ClickableText extends AbstractAction } } + @Override + public String toString() + { + return textLink; + } + public void execute() { if (!textLink.isEmpty() && gui.isClickableLinksEnabled() && attributeSet.getAttribute("type").equals("url")) @@ -231,6 +246,12 @@ public void actionPerformed(ActionEvent e) private void appendString(StyledDocument doc, String insertedString, SimpleAttributeSet style) throws BadLocationException { int position = doc.getLength(); + + // remove the existing attributes + style.removeAttribute("styleStart"); + style.removeAttribute("styleLength"); + style.removeAttribute("docLength"); + // add an attribute so we know when the style is expected to start and end. style.addAttribute("styleStart", position); style.addAttribute("styleLength", insertedString.length()); @@ -268,11 +289,6 @@ public void updateStyles(StyledDocument doc, int startPosition) SimpleAttributeSet matchingStyle = getStyle(styleName); - if(styleName.equalsIgnoreCase("urlStyle")) - { - System.out.println("sda"); - } - // Copy the attributes, but only if they aren't already set Iterator attributeIterator = textStyle.getAttributeNames().asIterator(); while(attributeIterator.hasNext()) @@ -367,49 +383,66 @@ public SimpleAttributeSet getStyleAtPosition(StyledDocument doc, int position, S return new SimpleAttributeSet(textStyle); } - private String parseClickableText(StyledDocument doc, IRCUser fromUser) throws BadLocationException + private void parseClickableText(StyledDocument doc, IRCUser fromUser, String line, SimpleAttributeSet defaultStyle) throws BadLocationException { HashMap regexStrings = new HashMap<>(); regexStrings.put(Constants.URL_REGEX, urlStyle()); regexStrings.put(Constants.CHANNEL_REGEX, channelStyle()); - final String line = getLatestLine(doc); + // final String line = getLatestLine(doc); final int relativePosition = getLinePosition(doc, getLatestLine(doc)); + ArrayList clickableLines = new ArrayList(); + for (Map.Entry entry : regexStrings.entrySet()) { String regex = entry.getKey(); - SimpleAttributeSet linkStyle = entry.getValue(); + Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(line); // do stuff for each match while (matcher.find()) { - - String clickableLine = line.substring(matcher.start(), matcher.end()); + SimpleAttributeSet linkStyle = getStyle(entry.getValue().getAttribute("name").toString()); + String clickableLine = matcher.group(1); linkStyle.addAttribute("clickableText", new ClickableText(clickableLine, linkStyle, fromUser)); - int styleStart = relativePosition + matcher.start(); - int styleLength = matcher.end() - matcher.start(); + int styleStart = relativePosition + matcher.start(1); + int styleLength = clickableLine.length(); linkStyle.addAttribute("styleStart", styleStart); linkStyle.addAttribute("styleLength", styleLength); - // update the styleLength of the previous style - SimpleAttributeSet oldStyle = getStyleAtPosition(doc, styleStart - 1, ""); - SimpleAttributeSet replaceStyle = getStyle(oldStyle.getAttribute("name").toString()); - int newStart = Integer.parseInt(oldStyle.getAttribute("styleStart").toString()); - int newLength = styleStart - Integer.parseInt(oldStyle.getAttribute("styleStart").toString()) + 1; - replaceStyle.addAttribute("styleStart", newStart); - replaceStyle.addAttribute("styleLength", newLength); - replaceStyle.addAttribute("docLength", oldStyle.getAttribute("docLength")); + clickableLines.add(linkStyle); + } + } - doc.setCharacterAttributes(newStart, newLength, replaceStyle, true); + clickableLines.sort((set1, set2) -> { + int styleStart1 = (int) set1.getAttribute("styleStart"); + int styleStart2 = (int) set2.getAttribute("styleStart"); + return Integer.compare(styleStart1, styleStart2); + }); - doc.setCharacterAttributes(styleStart, styleLength, linkStyle, true); - } + Iterator linesIterator = clickableLines.iterator(); + String remainingLine = line; + while (linesIterator.hasNext()) + { + SimpleAttributeSet nextLine = linesIterator.next(); + + // Offset based on the difference between the original line and the remaining line, + // plus the relativePosition within the document. + int offset = (line.length() - remainingLine.length()) + relativePosition; + int nextLineStart = Integer.parseInt(nextLine.getAttribute("styleStart").toString()); + int nextLineLength = Integer.parseInt(nextLine.getAttribute("styleLength").toString()); + + // Append the string that comes before the next clickable text + appendString(doc, remainingLine.substring(0, nextLineStart- offset), defaultStyle); + + appendString(doc, nextLine.getAttribute("clickableText").toString(), nextLine); + + remainingLine = remainingLine.substring((nextLineStart + nextLineLength) - offset); } - return line; + appendString(doc, remainingLine, defaultStyle); } /** @@ -420,8 +453,11 @@ private String parseClickableText(StyledDocument doc, IRCUser fromUser) throws B * @param fromUser * @param line */ - public void formattedDocument(StyledDocument doc, String timeLine, IRCUser fromUser, String fromString, String line) + public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUser, String fromString, String line) { + // build the timeLine string + String timeLine = UserGUI.getTimeLineString(lineDate); + if (fromUser != null && null != myNick && myNick.equals(fromUser.toString())) { nameStyle = this.myStyle(); @@ -441,13 +477,14 @@ public void formattedDocument(StyledDocument doc, String timeLine, IRCUser fromU lineStyle = defaultStyle(); } - timeStyle = defaultStyle(); + timeStyle = lineStyle; try { // doc.insertString(doc.getLength(), timeLine, timeStyle); - if(null != timeLine && !timeLine.isBlank()) + // if(null != timeLine && !timeLine.isBlank()) + if(null != lineDate) appendString(doc, timeLine + " ", timeStyle); appendString(doc, "<", lineStyle); @@ -467,10 +504,14 @@ public void formattedDocument(StyledDocument doc, String timeLine, IRCUser fromU appendString(doc, ">", lineStyle); // print the remaining text - appendString(doc, " "+line, lineStyle); + // appendString(doc, " "+line, lineStyle); // parse the outputted line for clickable text - parseClickableText(doc, fromUser); + parseClickableText(doc, fromUser, " "+line, lineStyle); + + // add the date to the end of the string to preserve the timestamp of the line + // when updating styles + lineStyle.addAttribute("date", lineDate); appendString(doc, System.getProperty("line.separator"), lineStyle); } catch (BadLocationException e) diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 5d05bdd..da6908c 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -853,16 +853,14 @@ public Component getListCellRendererComponent(JList list, Object value, int i previewTextArea.setCaretPosition(previewTextArea.getDocument().getLength()); - DateFormat chatDateFormat = new SimpleDateFormat("HHmm"); - Date chatDate = new Date(); - String timeLine = "[" + chatDateFormat.format(chatDate) + "]"; - - + IRCUser tempUser = new IRCUser(null, "matty_r"); + IRCUser tempUser2 = new IRCUser(null, "urChatClient"); previewLineFormatter.setNick("urChatClient"); - previewLineFormatter.formattedDocument(previewDoc, timeLine, null, "matty_r", "Hello, world!"); - previewLineFormatter.formattedDocument(previewDoc, timeLine, null, "matty_r", "Hello, urChatClient!"); - previewLineFormatter.formattedDocument(previewDoc, timeLine, null, "urChatClient", "Go to https://github.com/matty-r/urChat"); - previewLineFormatter.formattedDocument(previewDoc, timeLine, null, "urChatClient", "Join #urchatclient on irc.libera.chat"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), null, Constants.EVENT_USER, "urChat has loaded - this is an Event"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "Normal line. Hello, world!"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "This is what it looks like when your nick is mentioned, urChatClient!"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, "urChatClient", "Go to https://github.com/matty-r/urChat"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, "urChatClient", "Join #urchatclient on irc.libera.chat or #anotherroom"); // private static final JLabel timeStampFontLabel = new JLabel("Timestamp Font"); // private static final JButton otherNickFontLabel = new JButton("Other Nick Font"); @@ -878,6 +876,13 @@ public Component getListCellRendererComponent(JList list, Object value, int i // addToPanel(appearancePanel, timeStampFontButton); } + public static String getTimeLineString(Date date) + { + SimpleDateFormat chatDateFormat = new SimpleDateFormat(timeStampComponent.getAsTextField().getText()); + + return chatDateFormat.format(date); + } + private void setupInterfacePanel() { interfacePanel.add(showEventTicker); diff --git a/src/urChatBasic/frontend/utils/URColour.java b/src/urChatBasic/frontend/utils/URColour.java index 470884e..4765cab 100644 --- a/src/urChatBasic/frontend/utils/URColour.java +++ b/src/urChatBasic/frontend/utils/URColour.java @@ -4,7 +4,7 @@ public class URColour { - private static boolean useDarkColour(Color sourceColour) + public static boolean useDarkColour(Color sourceColour) { // Counting the perceptive luminance - human eye favors green color... double luminance = (0.299 * sourceColour.getRed() + 0.587 * sourceColour.getGreen() + 0.114 * sourceColour.getBlue()) / 255; diff --git a/src/urChatBasic/tests/backend/MessageHandlerTests.java b/src/urChatBasic/tests/backend/MessageHandlerTests.java index e8a190b..bbf0af8 100644 --- a/src/urChatBasic/tests/backend/MessageHandlerTests.java +++ b/src/urChatBasic/tests/backend/MessageHandlerTests.java @@ -10,7 +10,6 @@ import urChatBasic.frontend.DriverGUI; import urChatBasic.frontend.IRCServer; import urChatBasic.frontend.IRCUser; -import urChatBasic.frontend.LineFormatter.ClickableText; import urChatBasic.frontend.UserGUI; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; @@ -253,7 +252,7 @@ public void testServerLineLimit() throws BadLocationException, InterruptedExcept } @Test - public void emojiMessage() + public void _emojiMessage() { // test display of emojis in text String rawMessage = ":sd!~discord@user/sd PRIVMSG #somechannel :02 this should show a flag"; @@ -265,7 +264,7 @@ public void urlInMessage() throws BadLocationException, InterruptedException { // test displaying urls - String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG #somechannel :https://i.imgur.com/somepicture.png"; + String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG #somechannel :https://google.com"; // String rawMessage2 = "https://duckduckgo.com/?q=irc+urchat&kp=1&t=h_&ia=web"; Message testMessage = testHandler.new Message(rawMessage); @@ -294,7 +293,7 @@ public void channelRegex() String regexLine = ""; while (matcher.find()) { - regexLine = line.substring(matcher.start(), matcher.end()); + regexLine = matcher.group(1); } assertTrue(regexLine.equalsIgnoreCase("#urchatclient")); From 1d5bd093a991dd74ccbee1f9a3854014632eb601 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 4 Nov 2023 07:56:55 +1000 Subject: [PATCH 25/78] Fix positioning for when updating styles --- src/urChatBasic/frontend/LineFormatter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index a09d701..c526d85 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -284,7 +284,7 @@ public void updateStyles(StyledDocument doc, int startPosition) AttributeSet textStyle = doc.getCharacterElement(startPosition).getAttributes(); String styleName = textStyle.getAttribute("name").toString(); - int styleStart = Integer.parseInt(textStyle.getAttribute("styleStart").toString()); + int styleStart = startPosition; int styleLength = Integer.parseInt(textStyle.getAttribute("styleLength").toString()); SimpleAttributeSet matchingStyle = getStyle(styleName); From c068f1425797adee4e6365cd2d7e60d2b0998289 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 5 Nov 2023 06:04:50 +1000 Subject: [PATCH 26/78] Some refactoring --- src/urChatBasic/base/Constants.java | 3 +- src/urChatBasic/base/IRCRoomBase.java | 11 +---- src/urChatBasic/frontend/UserGUI.java | 67 ++++++++++++++++++--------- 3 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/urChatBasic/base/Constants.java b/src/urChatBasic/base/Constants.java index df48bca..acde3cb 100644 --- a/src/urChatBasic/base/Constants.java +++ b/src/urChatBasic/base/Constants.java @@ -53,6 +53,7 @@ public class Constants public static final String KEY_NICK_NAME = "nick name"; public static final String KEY_REAL_NAME = "real name"; public static final String KEY_TIME_STAMPS = "show time stamps"; + public static final String KEY_TIME_STAMP_FORMAT = "[HHmm]"; public static final String KEY_LAF_NAME = "laf name"; public static final String KEY_EVENT_TICKER_ACTIVE = "show event ticker"; public static final String KEY_USERS_LIST_ACTIVE = "show users list"; @@ -91,7 +92,7 @@ public class Constants public static final String DEFAULT_NICK_NAME = "urChatClient"; public static final String DEFAULT_REAL_NAME = "urChatClient"; public static final Boolean DEFAULT_TIME_STAMPS = true; - public static final String DEFAULT_TIME_STAMP_FORMAT = "HHmm"; + public static final String DEFAULT_TIME_STAMP_FORMAT = "[HHmm]"; public static final String DEFAULT_LAF_NAME = UIManager.getSystemLookAndFeelClassName(); public static final Boolean DEFAULT_EVENT_TICKER_ACTIVE = true; public static final Boolean DEFAULT_CLICKABLE_LINKS_ENABLED = true; diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 3fafd3f..d835635 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -487,13 +487,6 @@ public void run() return; } - DateFormat chatDateFormat = new SimpleDateFormat("HHmm"); - Date chatDate = new Date(); - String timeLine = ""; - - if (gui.isTimeStampsEnabled()) - timeLine = "[" + chatDateFormat.format(chatDate) + "]"; - if (gui.isChannelHistoryEnabled()) { try @@ -505,7 +498,7 @@ public void run() } } - StyledDocument doc = (StyledDocument) channelTextArea.getDocument(); + StyledDocument doc = channelTextArea.getStyledDocument(); IRCUser fromIRCUser = getCreatedUser(fromUser); // If we received a message from a user that isn't in the channel @@ -526,7 +519,7 @@ public void run() if (fromUser.equals(Constants.EVENT_USER) || !fromIRCUser.isMuted()) { - lineFormatter.formattedDocument(doc, new Date(), fromIRCUser, fromUser, line); + lineFormatter.formattedDocument(doc, gui.isTimeStampsEnabled() ? new Date() : null, fromIRCUser, fromUser, line); if (lineFormatter.nameStyle.getAttribute("name") == lineFormatter.highStyle() .getAttribute("name")) diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index da6908c..129067a 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -7,15 +7,14 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.List; import javax.swing.*; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.event.*; +import javax.swing.text.BadLocationException; import javax.swing.text.StyledDocument; -import javax.swing.text.StyledEditorKit; import urChatBasic.backend.utils.URUncaughtExceptionHandler; import urChatBasic.base.Constants; import urChatBasic.base.IRCRoomBase; @@ -75,7 +74,7 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase // Appearance Panel private FontPanel clientFontPanel; - private static final JTextField timeStampFormat = new JTextField(Constants.DEFAULT_TIME_STAMP_FORMAT); + private static final JTextField timeStampFormat = new JTextField(); private static final URComponent timeStampComponent = new URComponent("Timestamp Format:", timeStampFormat, Size.MEDIUM); private static final JLabel timeStampFontLabel = new JLabel("Timestamp Font"); private static final JButton otherNickFontLabel = new JButton("Other Nick Font"); @@ -838,30 +837,16 @@ public Component getListCellRendererComponent(JList list, Object value, int i lafOptions.addActionListener(new ChangeLAFListener()); clientFontPanel = new FontPanel(getFont(), getProfilePath(), "Global Font:"); - clientFontPanel.setPreferredSize(new Dimension(500, 64)); + clientFontPanel.setPreferredSize(new Dimension(700, 64)); clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); - // FontDialog timeStampFontDialog = new FontDialog("Timestamp Font:", UserGUI.this.getFont(), getProfilePath()); - // timeStampFontLabel.setFont - - StyledDocument previewDoc = (StyledDocument) previewTextArea.getDocument(); - - previewTextScroll.setPreferredSize(new Dimension(500, 200)); + previewTextScroll.setPreferredSize(new Dimension(700, 150)); previewTextArea.setEditable(false); - // previewTextArea.setFont(clientFontPanel.getFont()); - previewLineFormatter = new LineFormatter(clientFontPanel.getFont(), null); - previewTextArea.setCaretPosition(previewTextArea.getDocument().getLength()); - - IRCUser tempUser = new IRCUser(null, "matty_r"); - IRCUser tempUser2 = new IRCUser(null, "urChatClient"); - previewLineFormatter.setNick("urChatClient"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), null, Constants.EVENT_USER, "urChat has loaded - this is an Event"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "Normal line. Hello, world!"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "This is what it looks like when your nick is mentioned, urChatClient!"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, "urChatClient", "Go to https://github.com/matty-r/urChat"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, "urChatClient", "Join #urchatclient on irc.libera.chat or #anotherroom"); + // TODO: Add updatePreviewTextArea on keypress in the timeStampFormat + // timeStampFormat.addActionListener( ); + updatePreviewTextArea(); // private static final JLabel timeStampFontLabel = new JLabel("Timestamp Font"); // private static final JButton otherNickFontLabel = new JButton("Other Nick Font"); // private static final JButton userNickFontLabel = new JButton("My Nick Font"); @@ -876,6 +861,35 @@ public Component getListCellRendererComponent(JList list, Object value, int i // addToPanel(appearancePanel, timeStampFontButton); } + public void updatePreviewTextArea() + { + StyledDocument previewDoc = previewTextArea.getStyledDocument(); + + try + { + // Clear all text + previewDoc.remove(0, previewDoc.getLength()); + } catch (BadLocationException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + // previewTextArea.setFont(clientFontPanel.getFont()); + previewLineFormatter = new LineFormatter(clientFontPanel.getFont(), null); + + previewTextArea.setCaretPosition(previewTextArea.getDocument().getLength()); + + IRCUser tempUser = new IRCUser(null, "matty_r"); + IRCUser tempUser2 = new IRCUser(null, System.getProperty("user.name")); + previewLineFormatter.setNick(System.getProperty("user.name")); + previewLineFormatter.formattedDocument(previewDoc, new Date(), null, Constants.EVENT_USER, "urChat has loaded - this is an Event"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "Normal line. Hello, world!"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "This is what it looks like when your nick is mentioned, "+System.getProperty("user.name")+"!"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), "Go to https://github.com/matty-r/urChat"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), "Join #urchatclient on irc.libera.chat or #anotherroom"); + } + public static String getTimeLineString(Date date) { SimpleDateFormat chatDateFormat = new SimpleDateFormat(timeStampComponent.getAsTextField().getText()); @@ -1494,6 +1508,10 @@ public void getClientSettings(boolean loadWindowSettings) clientFontPanel.loadFont(); + timeStampFormat.setText( + getProfilePath().get(Constants.KEY_TIME_STAMP_FORMAT, Constants.DEFAULT_TIME_STAMP_FORMAT) + ); + eventTickerDelay.setValue( getProfilePath().getInt(Constants.KEY_EVENT_TICKER_DELAY, Constants.DEFAULT_EVENT_TICKER_DELAY)); autoConnectToFavourites.setSelected(getProfilePath().getBoolean(Constants.KEY_AUTO_CONNECT_FAVOURITES, @@ -1743,6 +1761,8 @@ public void actionPerformed(ActionEvent arg0) favouriteItem.favFontDialog.getFontPanel().setDefaultFont(clientFontPanel.getFont()); favouriteItem.favFontDialog.getFontPanel().loadFont(); } + + previewLineFormatter.setFont(previewTextArea.getStyledDocument(), clientFontPanel.getFont()); } } @@ -1882,7 +1902,8 @@ private void updateExtras() } // update the styles in the preview text area - previewLineFormatter.updateStyles(previewTextArea.getStyledDocument(), 0); + // previewLineFormatter.updateStyles(previewTextArea.getStyledDocument(), 0); + updatePreviewTextArea(); } /* From 4c540085d49545753ae7bbcd3c732825b934753e Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 8 Nov 2023 05:19:47 +1000 Subject: [PATCH 27/78] clickable links in preview. working on getting the time format updated when running updateStyles --- src/urChatBasic/frontend/LineFormatter.java | 65 ++++++++++-- src/urChatBasic/frontend/UserGUI.java | 105 ++++++++++++++++---- 2 files changed, 139 insertions(+), 31 deletions(-) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index c526d85..cc42873 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -5,6 +5,7 @@ import java.awt.Font; import java.awt.event.ActionEvent; import java.net.URL; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -188,7 +189,7 @@ public String toString() public void execute() { - if (!textLink.isEmpty() && gui.isClickableLinksEnabled() && attributeSet.getAttribute("type").equals("url")) + if (!textLink.isEmpty() && attributeSet.getAttribute("type").equals("url")) { try { AtomicBoolean doOpenLink = new AtomicBoolean(false); @@ -243,10 +244,9 @@ public void actionPerformed(ActionEvent e) } } - private void appendString(StyledDocument doc, String insertedString, SimpleAttributeSet style) throws BadLocationException + // Inserts the string at the position + private void insertString(StyledDocument doc, String insertedString, SimpleAttributeSet style, int position) throws BadLocationException { - int position = doc.getLength(); - // remove the existing attributes style.removeAttribute("styleStart"); style.removeAttribute("styleLength"); @@ -259,6 +259,14 @@ private void appendString(StyledDocument doc, String insertedString, SimpleAttri doc.insertString(position, insertedString, style); } + // Adds the string (with all needed attributes) to the end of the document + private void appendString(StyledDocument doc, String insertedString, SimpleAttributeSet style) throws BadLocationException + { + int position = doc.getLength(); + + insertString(doc, insertedString, style, position); + } + private SimpleAttributeSet getStyle(String styleName) { switch (styleName) { @@ -281,7 +289,7 @@ private SimpleAttributeSet getStyle(String styleName) public void updateStyles(StyledDocument doc, int startPosition) { - AttributeSet textStyle = doc.getCharacterElement(startPosition).getAttributes(); + SimpleAttributeSet textStyle = new SimpleAttributeSet(doc.getCharacterElement(startPosition).getAttributes()); String styleName = textStyle.getAttribute("name").toString(); int styleStart = startPosition; @@ -289,13 +297,42 @@ public void updateStyles(StyledDocument doc, int startPosition) SimpleAttributeSet matchingStyle = getStyle(styleName); + // TODO: Update the time format. Check if there is a timeStyle already, if there is then remove it from the line + // and insert the new timeStyle/Format. Otherwise we just need to insert it. The first character/style will have + // the 'date' attribute of when the line was added. + + if (null != gui && null != textStyle.getAttribute("date")) + { + try + { + String newTimeString = gui.getTimeLineString((Date) textStyle.getAttribute("date")); + if (textStyle.getAttribute("type").toString().equalsIgnoreCase("time")) + { + doc.remove(styleStart, styleLength); + } + + if(gui.isTimeStampsEnabled()) + { + timeStyle.addAttribute("date", textStyle.getAttribute("date")); + textStyle.removeAttribute("date"); + doc.setCharacterAttributes(styleStart, styleLength, textStyle, true); + SimpleAttributeSet timeStyle = getStyle(styleName); + timeStyle.addAttribute("type", "time"); + insertString(doc, newTimeString, matchingStyle, styleStart); + styleStart += newTimeString.length(); + } + } catch (BadLocationException $ble) + { + // + } + } + // Copy the attributes, but only if they aren't already set Iterator attributeIterator = textStyle.getAttributeNames().asIterator(); while(attributeIterator.hasNext()) { String nextAttributeName = attributeIterator.next().toString(); - // get attribute "foreground" isn't working here despite foregrounf having been set if(matchingStyle.getAttribute(nextAttributeName) == null) { Iterator matchingIterator = matchingStyle.getAttributeNames().asIterator(); @@ -379,7 +416,6 @@ public SimpleAttributeSet getStyleAtPosition(StyledDocument doc, int position, S AttributeSet textStyle = doc.getCharacterElement(position).getAttributes(); - // String styleName = textStyle.getAttribute("name").toString(); return new SimpleAttributeSet(textStyle); } @@ -485,9 +521,20 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse // doc.insertString(doc.getLength(), timeLine, timeStyle); // if(null != timeLine && !timeLine.isBlank()) if(null != lineDate) + { + // add the date to the end of the string to preserve the timestamp of the line + // when updating styles + timeStyle.addAttribute("date", lineDate); + timeStyle.removeAttribute("type"); + timeStyle.addAttribute("type", "time"); appendString(doc, timeLine + " ", timeStyle); + timeStyle.removeAttribute("type"); + } else { + lineStyle.addAttribute("date", lineDate); + } appendString(doc, "<", lineStyle); + lineStyle.removeAttribute("date"); if(fromUser != null) { @@ -509,10 +556,6 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse // parse the outputted line for clickable text parseClickableText(doc, fromUser, " "+line, lineStyle); - // add the date to the end of the string to preserve the timestamp of the line - // when updating styles - lineStyle.addAttribute("date", lineDate); - appendString(doc, System.getProperty("line.separator"), lineStyle); } catch (BadLocationException e) { diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 129067a..524cf0a 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -5,6 +5,8 @@ import java.util.prefs.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.text.SimpleDateFormat; @@ -13,7 +15,9 @@ import javax.swing.*; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.event.*; +import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; +import javax.swing.text.Element; import javax.swing.text.StyledDocument; import urChatBasic.backend.utils.URUncaughtExceptionHandler; import urChatBasic.base.Constants; @@ -25,6 +29,7 @@ import urChatBasic.base.Constants.Size; import urChatBasic.base.capabilities.CapTypeBase; import urChatBasic.base.capabilities.CapabilityTypes; +import urChatBasic.frontend.LineFormatter.ClickableText; import urChatBasic.frontend.components.*; public class UserGUI extends JPanel implements Runnable, UserGUIBase @@ -843,8 +848,22 @@ public Component getListCellRendererComponent(JList list, Object value, int i previewTextScroll.setPreferredSize(new Dimension(700, 150)); previewTextArea.setEditable(false); - // TODO: Add updatePreviewTextArea on keypress in the timeStampFormat - // timeStampFormat.addActionListener( ); + timeStampFormat.addKeyListener(new KeyListener() { + @Override + public void keyTyped(KeyEvent e) { + // Not used + } + + @Override + public void keyPressed(KeyEvent e) { + // Not used + } + + @Override + public void keyReleased(KeyEvent e) { + updatePreviewTextArea(); + } + }); updatePreviewTextArea(); // private static final JLabel timeStampFontLabel = new JLabel("Timestamp Font"); @@ -865,29 +884,74 @@ public void updatePreviewTextArea() { StyledDocument previewDoc = previewTextArea.getStyledDocument(); - try - { - // Clear all text - previewDoc.remove(0, previewDoc.getLength()); - } catch (BadLocationException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } + // try + // { + // // Clear all text + // previewDoc.remove(0, previewDoc.getLength()); + // } catch (BadLocationException e) + // { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } // previewTextArea.setFont(clientFontPanel.getFont()); previewLineFormatter = new LineFormatter(clientFontPanel.getFont(), null); - previewTextArea.setCaretPosition(previewTextArea.getDocument().getLength()); + if(previewDoc.getLength() <= 0) + { + previewTextArea.setCaretPosition(previewTextArea.getDocument().getLength()); + previewTextArea.addMouseListener(new ChannelClickListener()); + previewTextArea.addMouseMotionListener(new ChannelMovementListener()); + IRCUser tempUser = new IRCUser(null, "matty_r"); + IRCUser tempUser2 = new IRCUser(null, System.getProperty("user.name")); + previewLineFormatter.setNick(System.getProperty("user.name")); + previewLineFormatter.formattedDocument(previewDoc, new Date(), null, Constants.EVENT_USER, "urChat has loaded - this is an Event"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "Normal line. Hello, world!"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "This is what it looks like when your nick is mentioned, "+System.getProperty("user.name")+"!"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), "Go to https://github.com/matty-r/urChat"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), "Join #urchatclient on irc.libera.chat or #anotherroom"); + } else { + previewLineFormatter.updateStyles(previewDoc, 0); + } + } - IRCUser tempUser = new IRCUser(null, "matty_r"); - IRCUser tempUser2 = new IRCUser(null, System.getProperty("user.name")); - previewLineFormatter.setNick(System.getProperty("user.name")); - previewLineFormatter.formattedDocument(previewDoc, new Date(), null, Constants.EVENT_USER, "urChat has loaded - this is an Event"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "Normal line. Hello, world!"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "This is what it looks like when your nick is mentioned, "+System.getProperty("user.name")+"!"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), "Go to https://github.com/matty-r/urChat"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), "Join #urchatclient on irc.libera.chat or #anotherroom"); + class ChannelClickListener extends MouseInputAdapter + { + public void mouseClicked(MouseEvent e) + { + StyledDocument doc = previewTextArea.getStyledDocument(); + Element ele = doc.getCharacterElement(previewTextArea.viewToModel2D((e.getPoint()))); + AttributeSet as = ele.getAttributes(); + ClickableText isClickableText = (ClickableText) as.getAttribute("clickableText"); + if (isClickableText != null && isClickableLinksEnabled()) + { + if (SwingUtilities.isRightMouseButton(e) && isClickableText.rightClickMenu() != null) + { + isClickableText.rightClickMenu().show(e.getComponent(), e.getX(), e.getY()); + } else if (SwingUtilities.isLeftMouseButton(e)) + { + isClickableText.execute(); + } + } + } + } + + class ChannelMovementListener extends MouseAdapter + { + public void mouseMoved(MouseEvent e) + { + StyledDocument doc = previewTextArea.getStyledDocument(); + Element wordElement = doc.getCharacterElement(previewTextArea.viewToModel2D((e.getPoint()))); + AttributeSet wordAttributeSet = wordElement.getAttributes(); + ClickableText isClickableText = (ClickableText) wordAttributeSet.getAttribute("clickableText"); + if (isClickableText != null && isClickableLinksEnabled()) + { + previewTextArea.setCursor(new Cursor(Cursor.HAND_CURSOR)); + } else + { + previewTextArea.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } } public static String getTimeLineString(Date date) @@ -1417,6 +1481,7 @@ public void setClientSettings() getProfilePath().put(Constants.KEY_NICK_NAME, userNameTextField.getText()); getProfilePath().put(Constants.KEY_REAL_NAME, realNameTextField.getText()); getProfilePath().putBoolean(Constants.KEY_TIME_STAMPS, enableTimeStamps.isSelected()); + getProfilePath().put(Constants.KEY_TIME_STAMP_FORMAT, timeStampFormat.getText()); getProfilePath().put(Constants.KEY_LAF_NAME, ((LookAndFeelInfo) lafOptions.getSelectedItem()).getClassName()); getProfilePath().putBoolean(Constants.KEY_EVENT_TICKER_ACTIVE, showEventTicker.isSelected()); getProfilePath().putBoolean(Constants.KEY_USERS_LIST_ACTIVE, showUsersList.isSelected()); From f673e976b582f6a2ffcdcbbd894dfda342b30e50 Mon Sep 17 00:00:00 2001 From: matty_r Date: Wed, 8 Nov 2023 06:14:34 +1000 Subject: [PATCH 28/78] More work --- src/urChatBasic/frontend/LineFormatter.java | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index cc42873..873c4e6 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -250,12 +250,10 @@ private void insertString(StyledDocument doc, String insertedString, SimpleAttri // remove the existing attributes style.removeAttribute("styleStart"); style.removeAttribute("styleLength"); - style.removeAttribute("docLength"); // add an attribute so we know when the style is expected to start and end. style.addAttribute("styleStart", position); style.addAttribute("styleLength", insertedString.length()); - style.addAttribute("docLength", doc.getLength()); doc.insertString(position, insertedString, style); } @@ -305,21 +303,30 @@ public void updateStyles(StyledDocument doc, int startPosition) { try { - String newTimeString = gui.getTimeLineString((Date) textStyle.getAttribute("date")); + Date lineDate = (Date) textStyle.getAttribute("date"); + String newTimeString = gui.getTimeLineString(lineDate); + boolean hasTime = false; + if (textStyle.getAttribute("type").toString().equalsIgnoreCase("time")) { + hasTime = true; doc.remove(styleStart, styleLength); } if(gui.isTimeStampsEnabled()) { - timeStyle.addAttribute("date", textStyle.getAttribute("date")); textStyle.removeAttribute("date"); - doc.setCharacterAttributes(styleStart, styleLength, textStyle, true); + textStyle.removeAttribute("time"); SimpleAttributeSet timeStyle = getStyle(styleName); + timeStyle.addAttribute("date", lineDate); timeStyle.addAttribute("type", "time"); - insertString(doc, newTimeString, matchingStyle, styleStart); - styleStart += newTimeString.length(); + insertString(doc, newTimeString, timeStyle, styleStart); + styleLength = newTimeString.length(); + styleStart += styleLength; + if(!hasTime) + doc.setCharacterAttributes(styleStart, styleLength, textStyle, true); + else + textStyle = timeStyle; } } catch (BadLocationException $ble) { From dd96a6d9a9589252a83e44b20850e5cec3ce32ef Mon Sep 17 00:00:00 2001 From: matty_r Date: Thu, 9 Nov 2023 06:15:59 +1000 Subject: [PATCH 29/78] more work on timestamp updating --- src/urChatBasic/frontend/LineFormatter.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 873c4e6..667ddb0 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -299,12 +299,14 @@ public void updateStyles(StyledDocument doc, int startPosition) // and insert the new timeStyle/Format. Otherwise we just need to insert it. The first character/style will have // the 'date' attribute of when the line was added. + boolean isDateStyle = false; if (null != gui && null != textStyle.getAttribute("date")) { + isDateStyle = true; try { Date lineDate = (Date) textStyle.getAttribute("date"); - String newTimeString = gui.getTimeLineString(lineDate); + String newTimeString = gui.getTimeLineString(lineDate) + " "; boolean hasTime = false; if (textStyle.getAttribute("type").toString().equalsIgnoreCase("time")) @@ -317,16 +319,15 @@ public void updateStyles(StyledDocument doc, int startPosition) { textStyle.removeAttribute("date"); textStyle.removeAttribute("time"); + + if(!hasTime) + doc.setCharacterAttributes(styleStart, styleLength, textStyle, true); + SimpleAttributeSet timeStyle = getStyle(styleName); timeStyle.addAttribute("date", lineDate); timeStyle.addAttribute("type", "time"); insertString(doc, newTimeString, timeStyle, styleStart); styleLength = newTimeString.length(); - styleStart += styleLength; - if(!hasTime) - doc.setCharacterAttributes(styleStart, styleLength, textStyle, true); - else - textStyle = timeStyle; } } catch (BadLocationException $ble) { @@ -358,7 +359,8 @@ public void updateStyles(StyledDocument doc, int startPosition) } } - doc.setCharacterAttributes(styleStart, styleLength, matchingStyle, true); + if(!isDateStyle) + doc.setCharacterAttributes(styleStart, styleLength, matchingStyle, true); if((styleStart + styleLength) < doc.getLength()) updateStyles(doc, (styleStart + styleLength)); @@ -527,7 +529,7 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse // doc.insertString(doc.getLength(), timeLine, timeStyle); // if(null != timeLine && !timeLine.isBlank()) - if(null != lineDate) + if(!timeLine.isBlank()) { // add the date to the end of the string to preserve the timestamp of the line // when updating styles From 3c962330dbff269d82ed733b213255b2c07c94f4 Mon Sep 17 00:00:00 2001 From: matty_r Date: Fri, 10 Nov 2023 06:27:22 +1000 Subject: [PATCH 30/78] Correctly adds/removes time stamp if the option is toggled --- src/urChatBasic/base/IRCRoomBase.java | 2 +- src/urChatBasic/frontend/LineFormatter.java | 23 +++++++++++++++++++-- src/urChatBasic/frontend/UserGUI.java | 2 ++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index d835635..53498bc 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -519,7 +519,7 @@ public void run() if (fromUser.equals(Constants.EVENT_USER) || !fromIRCUser.isMuted()) { - lineFormatter.formattedDocument(doc, gui.isTimeStampsEnabled() ? new Date() : null, fromIRCUser, fromUser, line); + lineFormatter.formattedDocument(doc, new Date(), fromIRCUser, fromUser, line); if (lineFormatter.nameStyle.getAttribute("name") == lineFormatter.highStyle() .getAttribute("name")) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 667ddb0..68674bd 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -309,7 +309,7 @@ public void updateStyles(StyledDocument doc, int startPosition) String newTimeString = gui.getTimeLineString(lineDate) + " "; boolean hasTime = false; - if (textStyle.getAttribute("type").toString().equalsIgnoreCase("time")) + if (null != textStyle.getAttribute("type") && textStyle.getAttribute("type").toString().equalsIgnoreCase("time")) { hasTime = true; doc.remove(styleStart, styleLength); @@ -328,6 +328,20 @@ public void updateStyles(StyledDocument doc, int startPosition) timeStyle.addAttribute("type", "time"); insertString(doc, newTimeString, timeStyle, styleStart); styleLength = newTimeString.length(); + } else { + if(hasTime) + { + textStyle = new SimpleAttributeSet(doc.getCharacterElement(startPosition).getAttributes()); + + styleName = textStyle.getAttribute("name").toString(); + styleStart = startPosition; + styleLength = Integer.parseInt(textStyle.getAttribute("styleLength").toString()); + + matchingStyle = getStyle(styleName); + matchingStyle.addAttribute("date", lineDate); + + isDateStyle = false; + } } } catch (BadLocationException $ble) { @@ -500,6 +514,10 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin */ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUser, String fromString, String line) { + + if(null == lineDate) + System.out.println("test"); + // build the timeLine string String timeLine = UserGUI.getTimeLineString(lineDate); @@ -529,7 +547,7 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse // doc.insertString(doc.getLength(), timeLine, timeStyle); // if(null != timeLine && !timeLine.isBlank()) - if(!timeLine.isBlank()) + if(!timeLine.isBlank() && gui.isTimeStampsEnabled()) { // add the date to the end of the string to preserve the timestamp of the line // when updating styles @@ -538,6 +556,7 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse timeStyle.addAttribute("type", "time"); appendString(doc, timeLine + " ", timeStyle); timeStyle.removeAttribute("type"); + lineStyle.removeAttribute("date"); } else { lineStyle.addAttribute("date", lineDate); } diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 524cf0a..96d901d 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -1577,6 +1577,8 @@ public void getClientSettings(boolean loadWindowSettings) getProfilePath().get(Constants.KEY_TIME_STAMP_FORMAT, Constants.DEFAULT_TIME_STAMP_FORMAT) ); + updatePreviewTextArea(); + eventTickerDelay.setValue( getProfilePath().getInt(Constants.KEY_EVENT_TICKER_DELAY, Constants.DEFAULT_EVENT_TICKER_DELAY)); autoConnectToFavourites.setSelected(getProfilePath().getBoolean(Constants.KEY_AUTO_CONNECT_FAVOURITES, From 2d1213cc9921164f1b7dd04836a60cfb013053a1 Mon Sep 17 00:00:00 2001 From: matty_r Date: Sat, 11 Nov 2023 07:23:56 +1000 Subject: [PATCH 31/78] Added reset font functionality. For the UserGUI it sets it to the system font, for channels it sets it to the Global Font (UserGui) --- src/urChatBasic/frontend/UserGUI.java | 49 ++++++++++---- .../frontend/components/FontPanel.java | 36 +++++++++- .../frontend/components/URComponent.java | 65 ------------------- .../frontend/dialogs/FontDialog.java | 5 ++ 4 files changed, 75 insertions(+), 80 deletions(-) delete mode 100644 src/urChatBasic/frontend/components/URComponent.java diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 96d901d..4e2b9fa 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -63,7 +63,6 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase private static final JScrollPane interfaceScroller = new JScrollPane(interfacePanel); private static final JComboBox lafOptions = new JComboBox(UIManager.getInstalledLookAndFeels()); - private static final URComponent lafOptionsComponent = new URComponent("Theme:", lafOptions, Size.LARGE); private static final JCheckBox showEventTicker = new JCheckBox("Show Event Ticker"); private static final JCheckBox showUsersList = new JCheckBox("Show Users List"); @@ -79,8 +78,7 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase // Appearance Panel private FontPanel clientFontPanel; - private static final JTextField timeStampFormat = new JTextField(); - private static final URComponent timeStampComponent = new URComponent("Timestamp Format:", timeStampFormat, Size.MEDIUM); + private static final JTextField timeStampField = new JTextField(); private static final JLabel timeStampFontLabel = new JLabel("Timestamp Font"); private static final JButton otherNickFontLabel = new JButton("Other Nick Font"); private static final JButton userNickFontLabel = new JButton("My Nick Font"); @@ -534,7 +532,7 @@ private void setupRightOptionsPanel() setupAppearancePanel(); } - private static void addToPanel(JPanel targetPanel, Component newComponent, String label) + private static void addToPanel(JPanel targetPanel, Component newComponent, String label, Size targetSize) { int topSpacing = 6; @@ -544,7 +542,7 @@ private static void addToPanel(JPanel targetPanel, Component newComponent, Strin if(null != label && !label.isBlank()) { - addToPanel(targetPanel, new JLabel(label + ":"), null); + addToPanel(targetPanel, new JLabel(label + ":"), null, targetSize); // There is a label, so we want the added component to be aligned with the label topSpacing = 0; } @@ -566,6 +564,9 @@ private static void addToPanel(JPanel targetPanel, Component newComponent, Strin // Set constraints for newComponent layout.putConstraint(SpringLayout.NORTH, newComponent, topSpacing, SpringLayout.SOUTH, previousComponent); layout.putConstraint(SpringLayout.WEST, newComponent, LEFT_ALIGNED, SpringLayout.WEST, previousComponent); + + if(null != targetSize && newComponent instanceof JTextField) + ((JTextField) newComponent).setColumns(12); } else { // If it's the first component, align it against the targetPanel targetPanel.add(newComponent); @@ -573,6 +574,9 @@ private static void addToPanel(JPanel targetPanel, Component newComponent, Strin // Set constraints for newComponent when it's the first component layout.putConstraint(SpringLayout.NORTH, newComponent, topSpacing * 2, SpringLayout.NORTH, targetPanel); layout.putConstraint(SpringLayout.WEST, newComponent, LEFT_SPACING * 2, SpringLayout.WEST, targetPanel); + + if(null != targetSize && newComponent instanceof JTextField) + ((JTextField) newComponent).setColumns(12); } } @@ -828,7 +832,7 @@ private void setupConnectionLayout() private void setupAppearancePanel() { - addToPanel(appearancePanel, lafOptionsComponent, null); + addToPanel(appearancePanel, lafOptions, "Theme", Size.MEDIUM); // Set a custom renderer to display the look and feel names lafOptions.setRenderer(new DefaultListCellRenderer() { @@ -844,11 +848,12 @@ public Component getListCellRendererComponent(JList list, Object value, int i clientFontPanel = new FontPanel(getFont(), getProfilePath(), "Global Font:"); clientFontPanel.setPreferredSize(new Dimension(700, 64)); clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); + clientFontPanel.getResetButton().addActionListener(new ResetFontListener()); previewTextScroll.setPreferredSize(new Dimension(700, 150)); previewTextArea.setEditable(false); - timeStampFormat.addKeyListener(new KeyListener() { + timeStampField.addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent e) { // Not used @@ -873,10 +878,10 @@ public void keyReleased(KeyEvent e) { // private static final JButton mediumStyleFontLabel = new JButton("Medium Priority Text Font"); // private static final JButton highStyleFontLabel = new JButton("High Priority Text Font"); - addToPanel(appearancePanel, clientFontPanel, "Global Font"); - addToPanel(appearancePanel, timeStampComponent, null); + addToPanel(appearancePanel, clientFontPanel, "Global Font", null); + addToPanel(appearancePanel, timeStampField, "Timestamp Format", Size.MEDIUM); - addToPanel(appearancePanel, previewTextScroll, "Font Preview"); + addToPanel(appearancePanel, previewTextScroll, "Font Preview", null); // addToPanel(appearancePanel, timeStampFontButton); } @@ -956,7 +961,7 @@ public void mouseMoved(MouseEvent e) public static String getTimeLineString(Date date) { - SimpleDateFormat chatDateFormat = new SimpleDateFormat(timeStampComponent.getAsTextField().getText()); + SimpleDateFormat chatDateFormat = new SimpleDateFormat(timeStampField.getText()); return chatDateFormat.format(date); } @@ -1128,7 +1133,7 @@ protected class SaveChannelFontListener implements ActionListener @Override public void actionPerformed(ActionEvent arg0) { - for (int index = 0; index < tabbedPane.getComponents().length; index++) + for (int index = 0; index < tabbedPane.getTabCount(); index++) { Component tab = tabbedPane.getComponentAt(index); @@ -1481,7 +1486,7 @@ public void setClientSettings() getProfilePath().put(Constants.KEY_NICK_NAME, userNameTextField.getText()); getProfilePath().put(Constants.KEY_REAL_NAME, realNameTextField.getText()); getProfilePath().putBoolean(Constants.KEY_TIME_STAMPS, enableTimeStamps.isSelected()); - getProfilePath().put(Constants.KEY_TIME_STAMP_FORMAT, timeStampFormat.getText()); + getProfilePath().put(Constants.KEY_TIME_STAMP_FORMAT, timeStampField.getText()); getProfilePath().put(Constants.KEY_LAF_NAME, ((LookAndFeelInfo) lafOptions.getSelectedItem()).getClassName()); getProfilePath().putBoolean(Constants.KEY_EVENT_TICKER_ACTIVE, showEventTicker.isSelected()); getProfilePath().putBoolean(Constants.KEY_USERS_LIST_ACTIVE, showUsersList.isSelected()); @@ -1573,7 +1578,7 @@ public void getClientSettings(boolean loadWindowSettings) clientFontPanel.loadFont(); - timeStampFormat.setText( + timeStampField.setText( getProfilePath().get(Constants.KEY_TIME_STAMP_FORMAT, Constants.DEFAULT_TIME_STAMP_FORMAT) ); @@ -1833,6 +1838,22 @@ public void actionPerformed(ActionEvent arg0) } } + protected class ResetFontListener implements ActionListener + { + @Override + public void actionPerformed(ActionEvent arg0) + { + getProfilePath().put(Constants.KEY_FONT_FAMILY, Constants.DEFAULT_FONT_GENERAL.getFamily()); + getProfilePath().putBoolean(Constants.KEY_FONT_BOLD, Constants.DEFAULT_FONT_GENERAL.isBold()); + getProfilePath().putBoolean(Constants.KEY_FONT_ITALIC, Constants.DEFAULT_FONT_GENERAL.isItalic()); + getProfilePath().putInt(Constants.KEY_FONT_SIZE, Constants.DEFAULT_FONT_GENERAL.getSize()); + + clientFontPanel.loadFont(); + + clientFontPanel.getSaveButton().doClick(); + } + } + public UserGUI() { diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 9a5f0b3..1e33327 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -26,10 +26,12 @@ public class FontPanel extends JPanel private final JComboBox SIZES_COMBO_BOX = new JComboBox<>(FONT_SIZES); private final JCheckBox MAKE_BOLD = new JCheckBox("BOLD"); private final JCheckBox MAKE_ITALIC = new JCheckBox("ITALIC"); + private final JButton RESET_BUTTON = new JButton("Reset Font"); private final JButton SAVE_BUTTON = new JButton("Save Font"); // private String fontType = "New Font:"; // private JLabel fontTypeLabel = new JLabel("New Font:"); // private final JPanel TITLE_PANEL = new JPanel(new GridLayout(1,1)); + private final JPanel BUTTON_PANEL = new JPanel(new GridLayout(1, 2)); private final JPanel MAIN_PANEL = new JPanel(new GridLayout(2, 3)); private Font defaultFont; // private final JButton CANCEL_BUTTON = new JButton("Cancel"); @@ -60,8 +62,14 @@ public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) MAIN_PANEL.add(TEXT_PREVIEW); MAIN_PANEL.add(MAKE_BOLD); MAIN_PANEL.add(MAKE_ITALIC); - MAIN_PANEL.add(SAVE_BUTTON); + BUTTON_PANEL.add(RESET_BUTTON); + BUTTON_PANEL.add(SAVE_BUTTON); + + MAIN_PANEL.add(BUTTON_PANEL); + + + RESET_BUTTON.addActionListener(new ResetListener()); SAVE_BUTTON.addActionListener(new SaveListener()); FONT_COMBO_BOX.addItemListener(new FontSelectionChange()); SIZES_COMBO_BOX.addItemListener(new FontSelectionChange()); @@ -87,12 +95,29 @@ public JButton getSaveButton() return SAVE_BUTTON; } + public JButton getResetButton() + { + return RESET_BUTTON; + } + public void setDefaultFont(Font f) { defaultFont = f; loadFont(); } + // Deletes the saved font, then loads the "default" font. + // The default font for a channel is the Global Font, the default font + // the UserGUI is Constants.DEFAULT_FONT + public void resetFont() { + settingsPath.remove(Constants.KEY_FONT_BOLD); + settingsPath.remove(Constants.KEY_FONT_ITALIC); + settingsPath.remove(Constants.KEY_FONT_SIZE); + settingsPath.remove(Constants.KEY_FONT_FAMILY); + + loadFont(); + } + public void loadFont() { Font savedFont = defaultFont; @@ -200,6 +225,15 @@ public void actionPerformed(ActionEvent e) } } + class ResetListener implements ActionListener + { + @Override + public void actionPerformed(ActionEvent e) + { + FontPanel.this.resetFont(); + } + } + public void setSettingsPath(Preferences settingsPath) { this.settingsPath = settingsPath; diff --git a/src/urChatBasic/frontend/components/URComponent.java b/src/urChatBasic/frontend/components/URComponent.java deleted file mode 100644 index c532b78..0000000 --- a/src/urChatBasic/frontend/components/URComponent.java +++ /dev/null @@ -1,65 +0,0 @@ -package urChatBasic.frontend.components; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; - -import javax.swing.BoxLayout; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTextField; - -import urChatBasic.base.Constants.Size; - -public class URComponent extends JPanel { - private JLabel label; - private JComponent component; - private Size size; - - public URComponent(String labelText, JComponent component, Size size) { - this.label = new JLabel(labelText); - this.component = component; - this.size = size; - init(); - } - - private int convertSize() - { - switch (size) { - case LARGE: - return 240; - case MEDIUM: - return 160; - case SMALL: - return 80; - default: - return 60; - } - } - - private void init() { - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - - label.setAlignmentX( Component.LEFT_ALIGNMENT); - label.setPreferredSize( new Dimension(convertSize(), label.getPreferredSize().height)); - - component.setAlignmentX( Component.LEFT_ALIGNMENT); - component.setPreferredSize( new Dimension(convertSize(), component.getPreferredSize().height)); - add(label); - add(component); - } - - public JComponent getComponent() { - return component; - } - - public JTextField getAsTextField() - { - return (JTextField) getComponent(); - } - - public void setComponent(JComponent component) { - this.component = component; - } -} diff --git a/src/urChatBasic/frontend/dialogs/FontDialog.java b/src/urChatBasic/frontend/dialogs/FontDialog.java index b373d9b..2e0b375 100644 --- a/src/urChatBasic/frontend/dialogs/FontDialog.java +++ b/src/urChatBasic/frontend/dialogs/FontDialog.java @@ -48,6 +48,11 @@ public void addSaveListener(ActionListener newActionListener) fontPanel.getSaveButton().addActionListener(newActionListener); } + public void addResetListener(ActionListener newActionListener) + { + fontPanel.getResetButton().addActionListener(newActionListener); + } + public class ShowFontDialog implements ActionListener { @Override From 56cd43adbda2f85a9135ffa5d4825be9dab8614d Mon Sep 17 00:00:00 2001 From: matty_r Date: Sun, 12 Nov 2023 07:27:09 +1000 Subject: [PATCH 32/78] Adding style picker --- src/urChatBasic/frontend/LineFormatter.java | 27 ++++++++++++++----- src/urChatBasic/frontend/UserGUI.java | 23 ++++++++++------ .../frontend/components/FontPanel.java | 1 + 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 68674bd..617dbdd 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -285,6 +285,23 @@ private SimpleAttributeSet getStyle(String styleName) } } + public Font getStyleAsFont(String styleName) + { + SimpleAttributeSet fontStyle = getStyle(styleName); + + int savedFontBoldItalic = 0; + + if (StyleConstants.isBold(fontStyle)) + savedFontBoldItalic = Font.BOLD; + if (StyleConstants.isItalic(fontStyle)) + savedFontBoldItalic |= Font.ITALIC; + + Font styleFont = new Font(StyleConstants.getFontFamily(fontStyle), + savedFontBoldItalic, StyleConstants.getFontSize(fontStyle)); + + return styleFont; + } + public void updateStyles(StyledDocument doc, int startPosition) { SimpleAttributeSet textStyle = new SimpleAttributeSet(doc.getCharacterElement(startPosition).getAttributes()); @@ -306,7 +323,7 @@ public void updateStyles(StyledDocument doc, int startPosition) try { Date lineDate = (Date) textStyle.getAttribute("date"); - String newTimeString = gui.getTimeLineString(lineDate) + " "; + String newTimeString = UserGUI.getTimeLineString(lineDate) + " "; boolean hasTime = false; if (null != textStyle.getAttribute("type") && textStyle.getAttribute("type").toString().equalsIgnoreCase("time")) @@ -350,14 +367,14 @@ public void updateStyles(StyledDocument doc, int startPosition) } // Copy the attributes, but only if they aren't already set - Iterator attributeIterator = textStyle.getAttributeNames().asIterator(); + Iterator attributeIterator = textStyle.getAttributeNames().asIterator(); while(attributeIterator.hasNext()) { String nextAttributeName = attributeIterator.next().toString(); if(matchingStyle.getAttribute(nextAttributeName) == null) { - Iterator matchingIterator = matchingStyle.getAttributeNames().asIterator(); + Iterator matchingIterator = matchingStyle.getAttributeNames().asIterator(); boolean needsToBeSet = true; while(matchingIterator.hasNext()) @@ -514,10 +531,6 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin */ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUser, String fromString, String line) { - - if(null == lineDate) - System.out.println("test"); - // build the timeLine string String timeLine = UserGUI.getTimeLineString(lineDate); diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 4e2b9fa..f64baf0 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -87,6 +87,7 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase private static final JButton highStyleFontLabel = new JButton("High Priority Text Font"); private static final JTextPane previewTextArea = new JTextPane(); private static final JScrollPane previewTextScroll = new JScrollPane(previewTextArea); + private static final JLabel styleLabel = new JLabel("Mouse over text to view style, right-click to edit."); private static LineFormatter previewLineFormatter; @@ -882,6 +883,7 @@ public void keyReleased(KeyEvent e) { addToPanel(appearancePanel, timeStampField, "Timestamp Format", Size.MEDIUM); addToPanel(appearancePanel, previewTextScroll, "Font Preview", null); + addToPanel(appearancePanel, styleLabel, "Preview Style", null); // addToPanel(appearancePanel, timeStampFontButton); } @@ -928,15 +930,14 @@ public void mouseClicked(MouseEvent e) Element ele = doc.getCharacterElement(previewTextArea.viewToModel2D((e.getPoint()))); AttributeSet as = ele.getAttributes(); ClickableText isClickableText = (ClickableText) as.getAttribute("clickableText"); - if (isClickableText != null && isClickableLinksEnabled()) + if (SwingUtilities.isRightMouseButton(e)) { - if (SwingUtilities.isRightMouseButton(e) && isClickableText.rightClickMenu() != null) - { - isClickableText.rightClickMenu().show(e.getComponent(), e.getX(), e.getY()); - } else if (SwingUtilities.isLeftMouseButton(e)) - { - isClickableText.execute(); - } + String styleName = styleLabel.getText(); + FontDialog styleFontDialog = new FontDialog(styleName, previewLineFormatter.getStyleAsFont(styleName), getFavouritesPath()); + styleFontDialog.setVisible(true); + } else if (SwingUtilities.isLeftMouseButton(e) && null != isClickableText) + { + isClickableText.execute(); } } } @@ -949,6 +950,12 @@ public void mouseMoved(MouseEvent e) Element wordElement = doc.getCharacterElement(previewTextArea.viewToModel2D((e.getPoint()))); AttributeSet wordAttributeSet = wordElement.getAttributes(); ClickableText isClickableText = (ClickableText) wordAttributeSet.getAttribute("clickableText"); + + if(null != wordAttributeSet.getAttribute("name")) + styleLabel.setText(wordAttributeSet.getAttribute("name").toString()); + else + styleLabel.setText("Mouse over text to view style, right-click to edit."); + if (isClickableText != null && isClickableLinksEnabled()) { previewTextArea.setCursor(new Cursor(Cursor.HAND_CURSOR)); diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 1e33327..4820908 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -35,6 +35,7 @@ public class FontPanel extends JPanel private final JPanel MAIN_PANEL = new JPanel(new GridLayout(2, 3)); private Font defaultFont; // private final JButton CANCEL_BUTTON = new JButton("Cancel"); + // TODO: Add colour picker for foreground and background private Preferences settingsPath; From 1ab7918d6326ccb8a35c3290a27496fcd36a160c Mon Sep 17 00:00:00 2001 From: matty_r Date: Mon, 13 Nov 2023 06:34:42 +1000 Subject: [PATCH 33/78] More work on style picker --- src/urChatBasic/base/Constants.java | 2 +- src/urChatBasic/base/IRCRoomBase.java | 6 +-- src/urChatBasic/frontend/LineFormatter.java | 10 +++-- src/urChatBasic/frontend/UserGUI.java | 42 +++++++++++++++++---- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/urChatBasic/base/Constants.java b/src/urChatBasic/base/Constants.java index acde3cb..2b13008 100644 --- a/src/urChatBasic/base/Constants.java +++ b/src/urChatBasic/base/Constants.java @@ -53,7 +53,7 @@ public class Constants public static final String KEY_NICK_NAME = "nick name"; public static final String KEY_REAL_NAME = "real name"; public static final String KEY_TIME_STAMPS = "show time stamps"; - public static final String KEY_TIME_STAMP_FORMAT = "[HHmm]"; + public static final String KEY_TIME_STAMP_FORMAT = "timestamp format"; public static final String KEY_LAF_NAME = "laf name"; public static final String KEY_EVENT_TICKER_ACTIVE = "show event ticker"; public static final String KEY_USERS_LIST_ACTIVE = "show users list"; diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 53498bc..b904641 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -173,13 +173,13 @@ private void initRoom() roomPrefs = gui.getFavouritesPath().node(getServer().getName()).node(roomName); fontDialog = new FontDialog(roomName, gui.getFont(), roomPrefs); - lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer()); + lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer(), roomPrefs); } else { roomPrefs = gui.getFavouritesPath().node(roomName); fontDialog = new FontDialog(roomName, gui.getFont(), roomPrefs); - lineFormatter = new LineFormatter(getFontPanel().getFont(), null); + lineFormatter = new LineFormatter(getFontPanel().getFont(), null, roomPrefs); } setFont(getFontPanel().getFont()); @@ -240,7 +240,7 @@ public FontPanel getFontPanel() public void resetLineFormatter() { - lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer()); + lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer(), roomPrefs); } private void setupMainTextArea() diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 617dbdd..8248858 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -5,7 +5,6 @@ import java.awt.Font; import java.awt.event.ActionEvent; import java.net.URL; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -13,6 +12,7 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; +import java.util.prefs.Preferences; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.AbstractAction; @@ -35,15 +35,18 @@ public class LineFormatter private String myNick; private Font myFont; private IRCServerBase myServer; + private Preferences formatterPrefs; public SimpleAttributeSet defaultStyle; public SimpleAttributeSet timeStyle; public SimpleAttributeSet nameStyle; public SimpleAttributeSet lineStyle; protected UserGUI gui = DriverGUI.gui; - public LineFormatter(Font myFont, final IRCServerBase server) + public LineFormatter(Font myFont, final IRCServerBase server, Preferences formatterPrefs) { - // myNick = server.getNick(); + // TODO: Need to load attributes from formatterPrefs + this.formatterPrefs = formatterPrefs; + if(null != server) { @@ -96,6 +99,7 @@ public SimpleAttributeSet lowStyle() StyleConstants.setForeground(tempStyle, Color.LIGHT_GRAY); } + StyleConstants.setBold(tempStyle, formatterPrefs.node("lowStyle").getBoolean("font bold", StyleConstants.isBold(tempStyle))); return tempStyle; } diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index f64baf0..cff67a1 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -902,13 +902,13 @@ public void updatePreviewTextArea() // } // previewTextArea.setFont(clientFontPanel.getFont()); - previewLineFormatter = new LineFormatter(clientFontPanel.getFont(), null); + previewLineFormatter = new LineFormatter(clientFontPanel.getFont(), null, getProfilePath()); if(previewDoc.getLength() <= 0) { previewTextArea.setCaretPosition(previewTextArea.getDocument().getLength()); - previewTextArea.addMouseListener(new ChannelClickListener()); - previewTextArea.addMouseMotionListener(new ChannelMovementListener()); + previewTextArea.addMouseListener(new PreviewClickListener()); + previewTextArea.addMouseMotionListener(new PreviewMovementListener()); IRCUser tempUser = new IRCUser(null, "matty_r"); IRCUser tempUser2 = new IRCUser(null, System.getProperty("user.name")); previewLineFormatter.setNick(System.getProperty("user.name")); @@ -922,7 +922,7 @@ public void updatePreviewTextArea() } } - class ChannelClickListener extends MouseInputAdapter + class PreviewClickListener extends MouseInputAdapter { public void mouseClicked(MouseEvent e) { @@ -933,7 +933,35 @@ public void mouseClicked(MouseEvent e) if (SwingUtilities.isRightMouseButton(e)) { String styleName = styleLabel.getText(); - FontDialog styleFontDialog = new FontDialog(styleName, previewLineFormatter.getStyleAsFont(styleName), getFavouritesPath()); + FontDialog styleFontDialog = new FontDialog(styleName, previewLineFormatter.getStyleAsFont(styleName), getProfilePath().node(styleName)); + + styleFontDialog.addSaveListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) { + // TODO: Need to save attributes and updateStyles after.. + // Currently runs the save after updateStyles + previewLineFormatter.updateStyles(doc, 0); + } + + }); + + styleFontDialog.addResetListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) { + try { + getProfilePath().node(styleName).removeNode(); + } catch (BackingStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + previewLineFormatter.updateStyles(doc, 0); + } + + }); + styleFontDialog.setVisible(true); } else if (SwingUtilities.isLeftMouseButton(e) && null != isClickableText) { @@ -942,7 +970,7 @@ public void mouseClicked(MouseEvent e) } } - class ChannelMovementListener extends MouseAdapter + class PreviewMovementListener extends MouseAdapter { public void mouseMoved(MouseEvent e) { @@ -1997,7 +2025,6 @@ private void updateExtras() } // update the styles in the preview text area - // previewLineFormatter.updateStyles(previewTextArea.getStyledDocument(), 0); updatePreviewTextArea(); } @@ -2009,7 +2036,6 @@ private void updateExtras() @Override public void run() { - // Auto-generated method stub Thread.currentThread().setContextClassLoader(DriverGUI.contextClassLoader); Thread.currentThread().setUncaughtExceptionHandler(new URUncaughtExceptionHandler()); From 53795041178c6c14d6d0b22b7c9bdc0aa0255ae6 Mon Sep 17 00:00:00 2001 From: matty_r Date: Tue, 14 Nov 2023 06:37:53 +1000 Subject: [PATCH 34/78] move tests to their own directory --- {src/urChatBasic/tests => tests}/backend/DialogTests.java | 2 +- .../tests => tests}/backend/MessageHandlerTests.java | 2 +- {src/urChatBasic/tests => tests}/backend/UserGUITests.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename {src/urChatBasic/tests => tests}/backend/DialogTests.java (98%) rename {src/urChatBasic/tests => tests}/backend/MessageHandlerTests.java (99%) rename {src/urChatBasic/tests => tests}/backend/UserGUITests.java (97%) diff --git a/src/urChatBasic/tests/backend/DialogTests.java b/tests/backend/DialogTests.java similarity index 98% rename from src/urChatBasic/tests/backend/DialogTests.java rename to tests/backend/DialogTests.java index 57f8bad..33933a4 100644 --- a/src/urChatBasic/tests/backend/DialogTests.java +++ b/tests/backend/DialogTests.java @@ -1,4 +1,4 @@ -package urChatBasic.tests.backend; +package backend; import org.junit.Test; import urChatBasic.frontend.dialogs.MessageDialog; diff --git a/src/urChatBasic/tests/backend/MessageHandlerTests.java b/tests/backend/MessageHandlerTests.java similarity index 99% rename from src/urChatBasic/tests/backend/MessageHandlerTests.java rename to tests/backend/MessageHandlerTests.java index bbf0af8..f7657b2 100644 --- a/src/urChatBasic/tests/backend/MessageHandlerTests.java +++ b/tests/backend/MessageHandlerTests.java @@ -1,4 +1,4 @@ -package urChatBasic.tests.backend; +package backend; import org.junit.Before; import org.junit.Test; diff --git a/src/urChatBasic/tests/backend/UserGUITests.java b/tests/backend/UserGUITests.java similarity index 97% rename from src/urChatBasic/tests/backend/UserGUITests.java rename to tests/backend/UserGUITests.java index e3aa8d9..602ba81 100644 --- a/src/urChatBasic/tests/backend/UserGUITests.java +++ b/tests/backend/UserGUITests.java @@ -1,4 +1,4 @@ -package urChatBasic.tests.backend; +package backend; import org.junit.After; import org.junit.Before; From edcbda7a7423879a744171f442fb1a1af4c025c2 Mon Sep 17 00:00:00 2001 From: matty_r Date: Fri, 17 Nov 2023 06:15:28 +1000 Subject: [PATCH 35/78] Adding styling to defaultStyle. Started adding an actionlistener 'queue' for the font dialog --- src/urChatBasic/frontend/LineFormatter.java | 14 +++++--- src/urChatBasic/frontend/UserGUI.java | 5 +++ .../frontend/components/FontPanel.java | 32 ++++++++++++++++++- .../frontend/dialogs/FontDialog.java | 3 +- tests/TestRunner.java | 7 ++++ 5 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 tests/TestRunner.java diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 8248858..8b441b7 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -78,11 +78,15 @@ public SimpleAttributeSet defaultStyle() defaultStyle.addAttribute("name", "defaultStyle"); defaultStyle.addAttribute("type", "default"); // get the contrasting colour of the background colour - StyleConstants.setForeground(defaultStyle, URColour.getContrastColour(UIManager.getColor("Panel.background"))); - StyleConstants.setFontFamily(defaultStyle, myFont.getFamily()); - StyleConstants.setFontSize(defaultStyle, myFont.getSize()); - StyleConstants.setBold(defaultStyle, myFont.isBold()); - StyleConstants.setItalic(defaultStyle, myFont.isItalic()); + StyleConstants.setForeground(defaultStyle, + new Color(formatterPrefs.node("defaultStyle").getInt("font foreground", + URColour.getContrastColour(UIManager.getColor("Panel.background")).getRGB() + ))); + + StyleConstants.setFontFamily(defaultStyle, formatterPrefs.node("defaultStyle").get("font family", myFont.getFamily())); + StyleConstants.setFontSize(defaultStyle, formatterPrefs.node("defaultStyle").getInt("font size", myFont.getSize())); + StyleConstants.setBold(defaultStyle, formatterPrefs.node("defaultStyle").getBoolean("font bold", myFont.isBold())); + StyleConstants.setItalic(defaultStyle, formatterPrefs.node("defaultStyle").getBoolean("font italic", myFont.isItalic())); return defaultStyle; } diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index cff67a1..7d2b36c 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -939,6 +939,10 @@ public void mouseClicked(MouseEvent e) @Override public void actionPerformed(ActionEvent arg0) { + + List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); + + // TODO: Need to save attributes and updateStyles after.. // Currently runs the save after updateStyles previewLineFormatter.updateStyles(doc, 0); @@ -962,6 +966,7 @@ public void actionPerformed(ActionEvent arg0) { }); + styleFontDialog.setVisible(true); } else if (SwingUtilities.isLeftMouseButton(e) && null != isClickableText) { diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 4820908..f50084a 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -1,5 +1,6 @@ package urChatBasic.frontend.components; +import java.awt.Component; import java.awt.Font; import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; @@ -9,6 +10,8 @@ import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.List; import java.util.prefs.Preferences; import javax.swing.*; import urChatBasic.base.Constants; @@ -37,6 +40,8 @@ public class FontPanel extends JPanel // private final JButton CANCEL_BUTTON = new JButton("Cancel"); // TODO: Add colour picker for foreground and background + private List actionListeners = new ArrayList<>(); + private Preferences settingsPath; public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) @@ -71,7 +76,8 @@ public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) RESET_BUTTON.addActionListener(new ResetListener()); - SAVE_BUTTON.addActionListener(new SaveListener()); + // SAVE_BUTTON.addActionListener(new SaveListener()); + addActionListener(SAVE_BUTTON, new SaveListener()); FONT_COMBO_BOX.addItemListener(new FontSelectionChange()); SIZES_COMBO_BOX.addItemListener(new FontSelectionChange()); MAKE_BOLD.addActionListener(new CheckListener()); @@ -196,6 +202,30 @@ private void previewFont() )); } + // Override the addActionListener method to keep track of added listeners + public void addActionListener(JButton targetButton, ActionListener listener) { + actionListeners.add(listener); + targetButton.addActionListener(listener); + } + + // Using reflection - we check to see if the class implements the ActionListener interface + // private static boolean implementsActionListener(Component component) { + // Class[] interfaces = component.getClass().getInterfaces(); + // Class actionListenerClass = ActionListener.class; + + // for (Class iface : interfaces) { + // if (iface == actionListenerClass) { + // return true; + // } + // } + // return false; + // } + + // Method to retrieve all added listeners + public List getActionListeners() { + return actionListeners; + } + class CheckListener implements ActionListener { diff --git a/src/urChatBasic/frontend/dialogs/FontDialog.java b/src/urChatBasic/frontend/dialogs/FontDialog.java index 2e0b375..a1ec6bf 100644 --- a/src/urChatBasic/frontend/dialogs/FontDialog.java +++ b/src/urChatBasic/frontend/dialogs/FontDialog.java @@ -45,7 +45,8 @@ public void setVisible(boolean b) public void addSaveListener(ActionListener newActionListener) { - fontPanel.getSaveButton().addActionListener(newActionListener); + // fontPanel.getSaveButton().addActionListener(newActionListener); + fontPanel.addActionListener(fontPanel.getSaveButton(), newActionListener); } public void addResetListener(ActionListener newActionListener) diff --git a/tests/TestRunner.java b/tests/TestRunner.java new file mode 100644 index 0000000..efb5711 --- /dev/null +++ b/tests/TestRunner.java @@ -0,0 +1,7 @@ + +public class TestRunner { + + public static void main(String[] args) { + + } +} From e9db03436d5ee1732284066db7206da0cc652b30 Mon Sep 17 00:00:00 2001 From: matty_r Date: Fri, 17 Nov 2023 06:39:36 +1000 Subject: [PATCH 36/78] Creating a testrunner --- build/test-build-linux.sh | 41 +++++++++++++++++++++++++++++++++++++++ tests/TestRunner.java | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 build/test-build-linux.sh diff --git a/build/test-build-linux.sh b/build/test-build-linux.sh new file mode 100644 index 0000000..7f8c1b0 --- /dev/null +++ b/build/test-build-linux.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Save the current directory to a variable +current_dir=$(pwd) + +# Get the latest Git tag +latest_tag=$(git describe --tags --abbrev=0) + +# Clone the repository into a temporary directory +temp_dir=$(mktemp -d) +git clone . "$temp_dir" +cd "$temp_dir" + +# Checkout the latest Git tag in the temporary directory +git checkout --quiet "$latest_tag" + +# Update the UR_VERSION in Constants.java +sed -i "s/public static String UR_VERSION.*/public static String UR_VERSION = \"rel-$latest_tag\";/" src/urChatBasic/base/Constants.java + +# Compile the Java files, excluding specific files or directories +find src -name "*.java" ! -name "UIManagerDefaults.java" -exec javac -cp lib/*:. -d bin {} + +find tests -name "*.java" ! -name "UIManagerDefaults.java" -exec javac -cp lib/*:. -d bin/tests {} + + + +# Copy the images directory +mkdir -p bin/images +cp -r src/images/* bin/images/ + +# Copy the lib directory +cp -r "$current_dir/lib" "$temp_dir/" + +# Create a manifest file specifying the main class +echo "Main-Class: urChatBasic.frontend.DriverGUI" > manifest.txt + +# Create the JAR file with the manifest and compiled class files +mkdir -p "$current_dir/release" +jar -cfm "$current_dir/release/urchattestrunner.jar" manifest.txt -C "$temp_dir/bin" . + +# Clean up the temporary directory +cd .. +rm -rf "$temp_dir" diff --git a/tests/TestRunner.java b/tests/TestRunner.java index efb5711..cc5fbc9 100644 --- a/tests/TestRunner.java +++ b/tests/TestRunner.java @@ -2,6 +2,6 @@ public class TestRunner { public static void main(String[] args) { - + System.out.println("TestRunner executed successfully."); } } From 0fa166cfd6f8cbaba64e0227ea5321fad75224f5 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 17 Nov 2023 16:11:11 +1000 Subject: [PATCH 37/78] refactor the test runner --- build/test-build-linux.sh | 48 ++++++++++++++---------- src/urChatBasic/frontend/DriverGUI.java | 9 ++++- tests/TestRunner.java | 7 ---- tests/URTestRunner.java | 50 +++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 29 deletions(-) delete mode 100644 tests/TestRunner.java create mode 100644 tests/URTestRunner.java diff --git a/build/test-build-linux.sh b/build/test-build-linux.sh index 7f8c1b0..95d1846 100644 --- a/build/test-build-linux.sh +++ b/build/test-build-linux.sh @@ -3,38 +3,46 @@ # Save the current directory to a variable current_dir=$(pwd) -# Get the latest Git tag -latest_tag=$(git describe --tags --abbrev=0) - # Clone the repository into a temporary directory temp_dir=$(mktemp -d) git clone . "$temp_dir" cd "$temp_dir" -# Checkout the latest Git tag in the temporary directory -git checkout --quiet "$latest_tag" - -# Update the UR_VERSION in Constants.java -sed -i "s/public static String UR_VERSION.*/public static String UR_VERSION = \"rel-$latest_tag\";/" src/urChatBasic/base/Constants.java - -# Compile the Java files, excluding specific files or directories -find src -name "*.java" ! -name "UIManagerDefaults.java" -exec javac -cp lib/*:. -d bin {} + -find tests -name "*.java" ! -name "UIManagerDefaults.java" -exec javac -cp lib/*:. -d bin/tests {} + - +# Compile the Java files for the main jar +find src -name "*.java" -exec javac -cp "lib/*" -d "bin/" {} + # Copy the images directory -mkdir -p bin/images -cp -r src/images/* bin/images/ +cp -r "images" "bin/" # Copy the lib directory -cp -r "$current_dir/lib" "$temp_dir/" +cp -r "lib" "bin/" + +cd "bin" # Create a manifest file specifying the main class -echo "Main-Class: urChatBasic.frontend.DriverGUI" > manifest.txt +echo "Main-Class: urChatBasic.frontend.DriverGUI" > ../manifest.txt + +# Create the JAR file with the manifest and compiled class files, includes the lib and images directory in the created JAR file +jar -cfm "urChat.jar" ../manifest.txt . + +# Delete all the files we don't want included in the urTestRunner.jar +rm -rf "images" +rm -rf "urChatBasic" + +# Compile the Java files for the urTestRunner, using the urChat.jar as a source of the lib files +find ../tests -name "*.java" -exec javac -cp "urChat.jar:lib/*" -d . {} + + +# Move the main.jar back into the temp dir +mv "urChat.jar" ../ + +rm -rf "lib" + +# Create a manifest file for the test runner +echo "Main-Class: TestRunner" > ../testmanifest.txt + +jar -cfm "urTestRunner.jar" ../testmanifest.txt . -# Create the JAR file with the manifest and compiled class files -mkdir -p "$current_dir/release" -jar -cfm "$current_dir/release/urchattestrunner.jar" manifest.txt -C "$temp_dir/bin" . +mv "urTestRunner.jar" ../ # Clean up the temporary directory cd .. diff --git a/src/urChatBasic/frontend/DriverGUI.java b/src/urChatBasic/frontend/DriverGUI.java index 6326163..9ee1c03 100644 --- a/src/urChatBasic/frontend/DriverGUI.java +++ b/src/urChatBasic/frontend/DriverGUI.java @@ -25,9 +25,14 @@ public static void main(String[] args) throws IOException { Constants.init(); - URL imgPath = new URL(Constants.RESOURCES_DIR + "urChat Icon.png"); + try { + URL imgPath = new URL(Constants.RESOURCES_DIR + "urChat Icon.png"); - img = new ImageIcon(imgPath); + img = new ImageIcon(imgPath); + } catch (Exception e) + { + Constants.LOGGER.log(Level.INFO, "No Icon found."); + } Constants.LOGGER.log(Level.INFO, "Starting up.."); diff --git a/tests/TestRunner.java b/tests/TestRunner.java deleted file mode 100644 index cc5fbc9..0000000 --- a/tests/TestRunner.java +++ /dev/null @@ -1,7 +0,0 @@ - -public class TestRunner { - - public static void main(String[] args) { - System.out.println("TestRunner executed successfully."); - } -} diff --git a/tests/URTestRunner.java b/tests/URTestRunner.java new file mode 100644 index 0000000..a3cac6a --- /dev/null +++ b/tests/URTestRunner.java @@ -0,0 +1,50 @@ +import java.util.ArrayList; +import java.util.List; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import backend.DialogTests; +import backend.MessageHandlerTests; +import backend.UserGUITests; + + +public class URTestRunner { + + private static List testClasses; + private static List testFailures; + + public static void main (String[] args) + { + testFailures = new ArrayList<>(); + testClasses = new ArrayList<>(); + + testClasses.add(DialogTests.class); + testClasses.add(MessageHandlerTests.class); + testClasses.add(UserGUITests.class); + + + int totalRuns = 0; + int totalFails = 0; + + for (Class testClass : testClasses) { + Result result = JUnitCore.runClasses(testClass); + totalRuns += result.getRunCount(); + totalFails += result.getFailureCount(); + + for(Failure failure : result.getFailures()) + { + testFailures.add(failure); + } + } + + System.out.println("Total number of tests " + totalRuns); + System.out.println("Total number of tests failed " + totalFails); + + + for(Failure failure : testFailures) + { + System.out.println(failure.getMessage()); + + } + } +} From 28a29e2572ae92cad591f2a7275c070e464c81f0 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 17 Nov 2023 17:14:53 +1000 Subject: [PATCH 38/78] test --- build/test-build-linux.sh | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/build/test-build-linux.sh b/build/test-build-linux.sh index 95d1846..07f97c9 100644 --- a/build/test-build-linux.sh +++ b/build/test-build-linux.sh @@ -1,7 +1,7 @@ #!/bin/bash # Save the current directory to a variable -current_dir=$(pwd) +initial_dir=$(pwd) # Clone the repository into a temporary directory temp_dir=$(mktemp -d) @@ -9,41 +9,45 @@ git clone . "$temp_dir" cd "$temp_dir" # Compile the Java files for the main jar -find src -name "*.java" -exec javac -cp "lib/*" -d "bin/" {} + - -# Copy the images directory -cp -r "images" "bin/" - -# Copy the lib directory -cp -r "lib" "bin/" +find src -name "*.java" -exec javac -d "bin" {} + cd "bin" +# Copy the images directory +cp -r "$initial_dir/src/images" "." + # Create a manifest file specifying the main class echo "Main-Class: urChatBasic.frontend.DriverGUI" > ../manifest.txt # Create the JAR file with the manifest and compiled class files, includes the lib and images directory in the created JAR file jar -cfm "urChat.jar" ../manifest.txt . -# Delete all the files we don't want included in the urTestRunner.jar +# Delete all the files not needed to compile the test runner rm -rf "images" rm -rf "urChatBasic" +# Copy the lib directory +cp -r "$initial_dir/lib" "." + # Compile the Java files for the urTestRunner, using the urChat.jar as a source of the lib files -find ../tests -name "*.java" -exec javac -cp "urChat.jar:lib/*" -d . {} + +find ../tests -name "*.java" -exec javac -cp "urChat.jar" -d . {} + -# Move the main.jar back into the temp dir +# Move the main.jar back into the temp dir (we don't want it included in the test runner jar) mv "urChat.jar" ../ +# Don't need the lib folder included in the jar rm -rf "lib" # Create a manifest file for the test runner -echo "Main-Class: TestRunner" > ../testmanifest.txt +echo "Main-Class: URTestRunner" > ../testmanifest.txt +echo "Class-Path: urChat.jar lib/*" >> ../testmanifest.txt jar -cfm "urTestRunner.jar" ../testmanifest.txt . mv "urTestRunner.jar" ../ +java -jar "../urTestRunner.jar" + # Clean up the temporary directory cd .. rm -rf "$temp_dir" From b9ad540338d96feb55a181a46790212152d1d4f7 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 18 Nov 2023 05:56:09 +1000 Subject: [PATCH 39/78] Incorporate Jacoco for test code coverage --- build/test-build-linux.sh | 21 ++++++++++++++------- tests/URTestRunner.java | 5 +++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/build/test-build-linux.sh b/build/test-build-linux.sh index 07f97c9..65482eb 100644 --- a/build/test-build-linux.sh +++ b/build/test-build-linux.sh @@ -30,24 +30,31 @@ rm -rf "urChatBasic" cp -r "$initial_dir/lib" "." # Compile the Java files for the urTestRunner, using the urChat.jar as a source of the lib files -find ../tests -name "*.java" -exec javac -cp "urChat.jar" -d . {} + +find ../tests -name "*.java" -exec javac -cp "urChat.jar:./lib/*" -d . {} + # Move the main.jar back into the temp dir (we don't want it included in the test runner jar) mv "urChat.jar" ../ -# Don't need the lib folder included in the jar -rm -rf "lib" - # Create a manifest file for the test runner echo "Main-Class: URTestRunner" > ../testmanifest.txt -echo "Class-Path: urChat.jar lib/*" >> ../testmanifest.txt +echo "Class-Path: urChat.jar ./lib/*" >> ../testmanifest.txt jar -cfm "urTestRunner.jar" ../testmanifest.txt . +mv "lib" ../ mv "urTestRunner.jar" ../ -java -jar "../urTestRunner.jar" +cd ../ + +# run with jacoco agent to build coverage.exec +java -javaagent:lib/jacocoagent.jar=destfile=coverage.exec -cp "urChat.jar:lib/*:urTestRunner.jar" URTestRunner + +# build html report pointing to the source .java files +java -jar lib/jacococli.jar report coverage.exec --classfiles urChat.jar --html coverage --sourcefiles src/ + +mv "coverage" "$initial_dir" # Clean up the temporary directory -cd .. +cd "$initial_dir" + rm -rf "$temp_dir" diff --git a/tests/URTestRunner.java b/tests/URTestRunner.java index a3cac6a..7b71e1a 100644 --- a/tests/URTestRunner.java +++ b/tests/URTestRunner.java @@ -40,11 +40,12 @@ public static void main (String[] args) System.out.println("Total number of tests " + totalRuns); System.out.println("Total number of tests failed " + totalFails); - for(Failure failure : testFailures) { System.out.println(failure.getMessage()); - } + + // TestRunner doesn't exit when the tests are complete for some reason + System.exit(0); } } From 82d079450a6ef27b7b140989009f2da0f8c0f27b Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 18 Nov 2023 06:04:47 +1000 Subject: [PATCH 40/78] Update readme with test dependencies --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db5abb9..9ed8062 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,24 @@ urChat is a Java based IRC Client designed around simplicity and minimal resourc Contributions ====== -**Currently targeting ![Milestone v0.4.0](https://github.com/matty-r/urChat/milestone/3)** +**Currently targeting ![Milestone v0.4.0](https://github.com/matty-r/urChat/milestone/3)** If you would like to assist in the development of urChat take a look at the Issues associated with the project. Please let me know if you wish to tackle a certain issue. +Test Dependencies +====== +Dependencies required only for running the tests: + +Create a **lib** directory with the following files (Only required for running the tests): + +* ![Junit 4](https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar) +* ![Hamcrest Core](https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar) + +Extract jacocoagent.jar and jacococli.jar into the **lib** directory + +* ![Jacoco](https://search.maven.org/remotecontent?filepath=org/jacoco/jacoco/0.8.11/jacoco-0.8.11.zip) + + Usage ====== Ensure you've got Java 17 available on your system, download and run the latest JAR release (https://github.com/matty-r/urChat/releases). If you'd like to try out the Theme functionality, create a 'themes' directory next to the urChat.jar and download the FlatLAF.jar release and place within that directory. The theme can be selected under the client options page. From 0a77a8559e14e9e6943a9e7d12772db838e2ecf6 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 18 Nov 2023 06:07:11 +1000 Subject: [PATCH 41/78] Fix the links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9ed8062..7ce6e23 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,12 @@ Dependencies required only for running the tests: Create a **lib** directory with the following files (Only required for running the tests): -* ![Junit 4](https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar) -* ![Hamcrest Core](https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar) +* [Junit 4](https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar) +* [Hamcrest Core](https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar) Extract jacocoagent.jar and jacococli.jar into the **lib** directory -* ![Jacoco](https://search.maven.org/remotecontent?filepath=org/jacoco/jacoco/0.8.11/jacoco-0.8.11.zip) +* [Jacoco](https://search.maven.org/remotecontent?filepath=org/jacoco/jacoco/0.8.11/jacoco-0.8.11.zip) Usage From bc553a308d78b6264b16e0333e27fc32e14e2f12 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 19 Nov 2023 06:51:51 +1000 Subject: [PATCH 42/78] Create an xml report of the tests run --- tests/URTestRunner.java | 63 +++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/tests/URTestRunner.java b/tests/URTestRunner.java index 7b71e1a..7d44308 100644 --- a/tests/URTestRunner.java +++ b/tests/URTestRunner.java @@ -1,8 +1,12 @@ +import java.io.FileWriter; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.junit.runner.JUnitCore; +import org.junit.runner.Request; import org.junit.runner.Result; import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; import backend.DialogTests; import backend.MessageHandlerTests; import backend.UserGUITests; @@ -13,7 +17,7 @@ public class URTestRunner { private static List testClasses; private static List testFailures; - public static void main (String[] args) + public static void main (String[] args) throws IOException { testFailures = new ArrayList<>(); testClasses = new ArrayList<>(); @@ -22,30 +26,65 @@ public static void main (String[] args) testClasses.add(MessageHandlerTests.class); testClasses.add(UserGUITests.class); + // Create a RunListener to output test results as XML + RunListener listener = new JUnitXmlListener(new FileWriter("report/junit-report.xml")); + + // Create a Request object to encapsulate all test classes + Request request = Request.classes(testClasses.toArray(new Class[0])); int totalRuns = 0; int totalFails = 0; - for (Class testClass : testClasses) { - Result result = JUnitCore.runClasses(testClass); - totalRuns += result.getRunCount(); - totalFails += result.getFailureCount(); + JUnitCore core = new JUnitCore(); + core.addListener(listener); - for(Failure failure : result.getFailures()) - { - testFailures.add(failure); - } + // Run all tests together + Result result = core.run(request); + totalRuns += result.getRunCount(); + totalFails += result.getFailureCount(); + + for (Failure failure : result.getFailures()) { + testFailures.add(failure); } System.out.println("Total number of tests " + totalRuns); System.out.println("Total number of tests failed " + totalFails); - for(Failure failure : testFailures) - { + for (Failure failure : testFailures) { System.out.println(failure.getMessage()); } - // TestRunner doesn't exit when the tests are complete for some reason + System.out.println("Done"); + System.exit(0); } + + static class JUnitXmlListener extends RunListener { + private final FileWriter writer; + + public JUnitXmlListener(FileWriter writer) { + this.writer = writer; + } + + @Override + public void testRunFinished (Result result) throws IOException { + testRunFinishedXML(result); + } + + public void testRunFinishedXML(Result result) throws IOException { + writer.write(""); + + for (Failure failure : result.getFailures()) { + writer.write(""); + writer.write("" + failure.getTrace() + ""); + writer.write(""); + } + + writer.write(""); + writer.flush(); + writer.close(); + } + } } From 85be99c2c9b6497ef47101e966448aa1acf460fa Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 19 Nov 2023 06:58:13 +1000 Subject: [PATCH 43/78] test build script generates the reports in the report directory --- build/test-build-linux.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build/test-build-linux.sh b/build/test-build-linux.sh index 65482eb..4646843 100644 --- a/build/test-build-linux.sh +++ b/build/test-build-linux.sh @@ -46,13 +46,15 @@ mv "urTestRunner.jar" ../ cd ../ +mkdir -p "report" + # run with jacoco agent to build coverage.exec java -javaagent:lib/jacocoagent.jar=destfile=coverage.exec -cp "urChat.jar:lib/*:urTestRunner.jar" URTestRunner # build html report pointing to the source .java files -java -jar lib/jacococli.jar report coverage.exec --classfiles urChat.jar --html coverage --sourcefiles src/ +java -jar lib/jacococli.jar report coverage.exec --classfiles urChat.jar --html report --sourcefiles src/ -mv "coverage" "$initial_dir" +mv "report" "$initial_dir" # Clean up the temporary directory cd "$initial_dir" From 5e9cd7182f46c3106aaa038df1499a3679459312 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 19 Nov 2023 07:09:59 +1000 Subject: [PATCH 44/78] Create report directory if it doesn't exist --- tests/URTestRunner.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/URTestRunner.java b/tests/URTestRunner.java index 7d44308..9b347a3 100644 --- a/tests/URTestRunner.java +++ b/tests/URTestRunner.java @@ -1,3 +1,4 @@ +import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; @@ -26,6 +27,12 @@ public static void main (String[] args) throws IOException testClasses.add(MessageHandlerTests.class); testClasses.add(UserGUITests.class); + // Create the report directory if it doesn't exist + File reportDirectory = new File("report"); + if (!reportDirectory.exists()) { + reportDirectory.mkdirs(); // Create directory and any missing parent directories + } + // Create a RunListener to output test results as XML RunListener listener = new JUnitXmlListener(new FileWriter("report/junit-report.xml")); From 632d775a50f6d6e04f3a4dd37a1fa258e4b321b7 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 19 Nov 2023 17:31:28 +1000 Subject: [PATCH 45/78] Switch to using testng --- build/test-build-linux.sh | 0 tests/URTestRunner.java | 117 +++++++------------------ tests/backend/DialogTests.java | 2 +- tests/backend/MessageHandlerTests.java | 6 +- tests/backend/UserGUITests.java | 12 ++- 5 files changed, 40 insertions(+), 97 deletions(-) mode change 100644 => 100755 build/test-build-linux.sh diff --git a/build/test-build-linux.sh b/build/test-build-linux.sh old mode 100644 new mode 100755 diff --git a/tests/URTestRunner.java b/tests/URTestRunner.java index 9b347a3..8808ced 100644 --- a/tests/URTestRunner.java +++ b/tests/URTestRunner.java @@ -1,97 +1,42 @@ -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.junit.runner.JUnitCore; -import org.junit.runner.Request; -import org.junit.runner.Result; -import org.junit.runner.notification.Failure; -import org.junit.runner.notification.RunListener; +import org.testng.TestNG; +import org.testng.xml.XmlClass; +import org.testng.xml.XmlSuite; +import org.testng.xml.XmlTest; import backend.DialogTests; import backend.MessageHandlerTests; import backend.UserGUITests; +import java.util.ArrayList; +import java.util.List; +import org.testng.TestListenerAdapter; +public class URTestRunner { -public class URTestRunner { - - private static List testClasses; - private static List testFailures; - - public static void main (String[] args) throws IOException - { - testFailures = new ArrayList<>(); - testClasses = new ArrayList<>(); - - testClasses.add(DialogTests.class); - testClasses.add(MessageHandlerTests.class); - testClasses.add(UserGUITests.class); - - // Create the report directory if it doesn't exist - File reportDirectory = new File("report"); - if (!reportDirectory.exists()) { - reportDirectory.mkdirs(); // Create directory and any missing parent directories - } - - // Create a RunListener to output test results as XML - RunListener listener = new JUnitXmlListener(new FileWriter("report/junit-report.xml")); - - // Create a Request object to encapsulate all test classes - Request request = Request.classes(testClasses.toArray(new Class[0])); - - int totalRuns = 0; - int totalFails = 0; - - JUnitCore core = new JUnitCore(); - core.addListener(listener); - - // Run all tests together - Result result = core.run(request); - totalRuns += result.getRunCount(); - totalFails += result.getFailureCount(); - - for (Failure failure : result.getFailures()) { - testFailures.add(failure); - } - - System.out.println("Total number of tests " + totalRuns); - System.out.println("Total number of tests failed " + totalFails); - - for (Failure failure : testFailures) { - System.out.println(failure.getMessage()); - } - - System.out.println("Done"); - - System.exit(0); - } - - static class JUnitXmlListener extends RunListener { - private final FileWriter writer; - - public JUnitXmlListener(FileWriter writer) { - this.writer = writer; - } + public static void main(String[] args) { + // Create a TestNG instance + TestNG testNG = new TestNG(); - @Override - public void testRunFinished (Result result) throws IOException { - testRunFinishedXML(result); - } + // Define your test classes + List classes = new ArrayList<>(); + classes.add(DialogTests.class); + classes.add(MessageHandlerTests.class); + classes.add(UserGUITests.class); + // Add more test classes as needed - public void testRunFinishedXML(Result result) throws IOException { - writer.write(""); + // Set the test classes to TestNG + testNG.setTestClasses(classes.toArray(new Class[0])); - for (Failure failure : result.getFailures()) { - writer.write(""); - writer.write("" + failure.getTrace() + ""); - writer.write(""); - } + // Run TestNG + TestListenerAdapter listener = new TestListenerAdapter(); + testNG.addListener(listener); - writer.write(""); - writer.flush(); - writer.close(); + try { + testNG.run(); + } catch (Exception e) + { + System.out.println("test"); } + // Get test results + System.out.println("Total tests run: " + listener.getPassedTests().size()); + System.out.println("Total tests failed: " + listener.getFailedTests().size()); } -} +} \ No newline at end of file diff --git a/tests/backend/DialogTests.java b/tests/backend/DialogTests.java index 33933a4..e3d98b2 100644 --- a/tests/backend/DialogTests.java +++ b/tests/backend/DialogTests.java @@ -1,12 +1,12 @@ package backend; -import org.junit.Test; import urChatBasic.frontend.dialogs.MessageDialog; import urChatBasic.frontend.dialogs.YesNoDialog; import static org.junit.Assert.*; import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.JButton; import javax.swing.JOptionPane; +import org.testng.annotations.Test; public class DialogTests { diff --git a/tests/backend/MessageHandlerTests.java b/tests/backend/MessageHandlerTests.java index f7657b2..526a67d 100644 --- a/tests/backend/MessageHandlerTests.java +++ b/tests/backend/MessageHandlerTests.java @@ -1,7 +1,5 @@ package backend; -import org.junit.Before; -import org.junit.Test; import urChatBasic.backend.Connection; import urChatBasic.backend.MessageHandler; import urChatBasic.backend.MessageHandler.Message; @@ -21,6 +19,8 @@ import javax.swing.text.BadLocationException; import javax.swing.text.StyledDocument; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; public class MessageHandlerTests { MessageHandler testHandler; @@ -30,7 +30,7 @@ public class MessageHandlerTests { IRCUser testUser; Connection testConnection; - @Before + @BeforeTest public void setUp() throws Exception { DriverGUI.createGUI(); testGUI = DriverGUI.gui; diff --git a/tests/backend/UserGUITests.java b/tests/backend/UserGUITests.java index 602ba81..c01af1c 100644 --- a/tests/backend/UserGUITests.java +++ b/tests/backend/UserGUITests.java @@ -1,12 +1,10 @@ package backend; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; - +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; import urChatBasic.base.Constants; import static org.junit.Assert.*; @@ -16,7 +14,7 @@ public class UserGUITests { Preferences serverTestPreference; Preferences roomTestPreference; - @Before + @BeforeTest public void setUp() throws Exception { baseTestPreference = Constants.BASE_PREFS.parent().node("testing"); serverTestPreference = baseTestPreference.node("servername"); @@ -39,7 +37,7 @@ public void nodeNotEmpty() throws BackingStoreException { assertNotEquals(0, roomTestPreference.keys().length + roomTestPreference.childrenNames().length); } - @After + @AfterTest public void tearDown() throws BackingStoreException { baseTestPreference.removeNode(); } From 33556701c4de742bd346d108d534f77163e02918 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 19 Nov 2023 17:36:24 +1000 Subject: [PATCH 46/78] Move the TestNG output into the initial directory --- build/test-build-linux.sh | 4 ++++ tests/URTestRunner.java | 10 ++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/build/test-build-linux.sh b/build/test-build-linux.sh index 4646843..30033c8 100755 --- a/build/test-build-linux.sh +++ b/build/test-build-linux.sh @@ -54,8 +54,12 @@ java -javaagent:lib/jacocoagent.jar=destfile=coverage.exec -cp "urChat.jar:lib/* # build html report pointing to the source .java files java -jar lib/jacococli.jar report coverage.exec --classfiles urChat.jar --html report --sourcefiles src/ +# Jacoco Output mv "report" "$initial_dir" +# TestNG Output +mv "test-output" "$initial_dir" + # Clean up the temporary directory cd "$initial_dir" diff --git a/tests/URTestRunner.java b/tests/URTestRunner.java index 8808ced..f9a9073 100644 --- a/tests/URTestRunner.java +++ b/tests/URTestRunner.java @@ -29,14 +29,12 @@ public static void main(String[] args) { TestListenerAdapter listener = new TestListenerAdapter(); testNG.addListener(listener); - try { - testNG.run(); - } catch (Exception e) - { - System.out.println("test"); - } + testNG.run(); + // Get test results System.out.println("Total tests run: " + listener.getPassedTests().size()); System.out.println("Total tests failed: " + listener.getFailedTests().size()); + + System.exit(0); } } \ No newline at end of file From 7424f1fb85146f2fff4ce88ee7e30d90138e452e Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 20 Nov 2023 06:20:24 +1000 Subject: [PATCH 47/78] Ignore report directories --- .gitignore | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 6ea54cb..13b8e83 100644 --- a/.gitignore +++ b/.gitignore @@ -84,10 +84,10 @@ Logs/* .vscode/* out/* lib/* -themes/* -src/urChatBasic/backend/JoinClassLoader.java -src/urChatBasic/frontend/utils/UIManagerDefaults.java +themes release +test-output +report # not tested -build/tag-build-win.ps1 +build/tag-build-win.ps1 \ No newline at end of file From 47edde54cc7a27542743ae1e26929ac4a0dca147 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 20 Nov 2023 13:06:41 +1000 Subject: [PATCH 48/78] Added from reporter logging --- README.md | 6 +- tests/URTestRunner.java | 9 -- tests/backend/DialogTests.java | 8 +- tests/backend/MessageHandlerTests.java | 168 +++++++++++++++---------- 4 files changed, 115 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 7ce6e23..7165bc1 100644 --- a/README.md +++ b/README.md @@ -13,16 +13,18 @@ Test Dependencies ====== Dependencies required only for running the tests: -Create a **lib** directory with the following files (Only required for running the tests): +Create a **lib** directory with the following files: * [Junit 4](https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar) * [Hamcrest Core](https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar) +* [TestNG 7.8.0](https://repo1.maven.org/maven2/org/testng/testng/7.8.0/testng-7.8.0.jar) +* [JCommander](https://repo1.maven.org/maven2/com/beust/jcommander/1.82/jcommander-1.82.jar) +* [SLF4J](https://repo1.maven.org/maven2/org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9.jar) Extract jacocoagent.jar and jacococli.jar into the **lib** directory * [Jacoco](https://search.maven.org/remotecontent?filepath=org/jacoco/jacoco/0.8.11/jacoco-0.8.11.zip) - Usage ====== Ensure you've got Java 17 available on your system, download and run the latest JAR release (https://github.com/matty-r/urChat/releases). If you'd like to try out the Theme functionality, create a 'themes' directory next to the urChat.jar and download the FlatLAF.jar release and place within that directory. The theme can be selected under the client options page. diff --git a/tests/URTestRunner.java b/tests/URTestRunner.java index f9a9073..49bf4e4 100644 --- a/tests/URTestRunner.java +++ b/tests/URTestRunner.java @@ -1,7 +1,4 @@ import org.testng.TestNG; -import org.testng.xml.XmlClass; -import org.testng.xml.XmlSuite; -import org.testng.xml.XmlTest; import backend.DialogTests; import backend.MessageHandlerTests; import backend.UserGUITests; @@ -12,7 +9,6 @@ public class URTestRunner { public static void main(String[] args) { - // Create a TestNG instance TestNG testNG = new TestNG(); // Define your test classes @@ -20,7 +16,6 @@ public static void main(String[] args) { classes.add(DialogTests.class); classes.add(MessageHandlerTests.class); classes.add(UserGUITests.class); - // Add more test classes as needed // Set the test classes to TestNG testNG.setTestClasses(classes.toArray(new Class[0])); @@ -31,10 +26,6 @@ public static void main(String[] args) { testNG.run(); - // Get test results - System.out.println("Total tests run: " + listener.getPassedTests().size()); - System.out.println("Total tests failed: " + listener.getFailedTests().size()); - System.exit(0); } } \ No newline at end of file diff --git a/tests/backend/DialogTests.java b/tests/backend/DialogTests.java index e3d98b2..ef1b1e7 100644 --- a/tests/backend/DialogTests.java +++ b/tests/backend/DialogTests.java @@ -6,6 +6,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.JButton; import javax.swing.JOptionPane; +import org.testng.Reporter; import org.testng.annotations.Test; public class DialogTests @@ -42,7 +43,7 @@ public void testMessageDialog() assertTrue("Didn't press the cancel button", passedTest.get()); } - @Test + @Test(groups = {"Test #001"}) public void testYesNoDialogWithBoolean() { AtomicBoolean cancelClicked = new AtomicBoolean(false); @@ -63,11 +64,16 @@ public void testYesNoDialogWithBoolean() // Assert that the cancel action was executed assertTrue("No button wasn't pressed.", cancelClicked.get()); + + Reporter.log("Other reporting information for this test"); } @Test public void testYesNoDialogWithActionListener() { + + Reporter.log("Custom reporting log information here, defined in the method"); + // effectively final AtomicBoolean passedTest = new AtomicBoolean(false); diff --git a/tests/backend/MessageHandlerTests.java b/tests/backend/MessageHandlerTests.java index 526a67d..f7be8e5 100644 --- a/tests/backend/MessageHandlerTests.java +++ b/tests/backend/MessageHandlerTests.java @@ -19,10 +19,14 @@ import javax.swing.text.BadLocationException; import javax.swing.text.StyledDocument; -import org.testng.annotations.BeforeTest; +import org.testng.Reporter; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; import org.testng.annotations.Test; -public class MessageHandlerTests { +public class MessageHandlerTests +{ MessageHandler testHandler; IRCServer testServer; UserGUI testGUI; @@ -30,11 +34,13 @@ public class MessageHandlerTests { IRCUser testUser; Connection testConnection; - @BeforeTest - public void setUp() throws Exception { + @BeforeMethod(alwaysRun = true) + public void setUp() throws Exception + { DriverGUI.createGUI(); testGUI = DriverGUI.gui; - testServer = new IRCServer("testServer", "testUser", "testUser", "testPassword", "1337", true, "testProxy", "1234", true); + testServer = new IRCServer("testServer", "testUser", "testUser", "testPassword", "1337", true, "testProxy", + "1234", true); testUser = new IRCUser(testServer, "testUser"); testServer.addToPrivateRooms(testUser); testChannel = testServer.getCreatedPrivateRoom(testUser.toString()); @@ -42,44 +48,51 @@ public void setUp() throws Exception { testConnection = new Connection(testServer); } - @Test - public void noticeMessageParseTest() + @Test(groups = {"Test #001"}) + public void nickIsHighStyleTest() throws BadLocationException, InterruptedException { - String rawMessage = ":ChanServ!ChanServ@services.libera.chat NOTICE userName :[#somechannel] Welcome to #someChannel."; + String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG testUser :hello testUser!"; Message testMessage = testHandler.new Message(rawMessage); + testHandler.parseMessage(testMessage); + StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); + String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] hello testUser!" - assertEquals("#somechannel", testMessage.getChannel()); - // assertEquals("Welcome to #somechannel.", testMessage.getBody()); + while (testChannel.messageQueueWorking()) + { + TimeUnit.SECONDS.sleep(1); + } + + // Should be highStyle because someuser mentioned my nick, testUser + assertEquals("highStyle", + testChannel.getLineFormatter().getStyleAtPosition(testDoc, 11, testLine).getAttribute("name")); } - @Test + @Test(groups = {"Test #001"}) public void recvActionMessage() { - String rawMessage = ":"+testUser+"!~"+testUser+"@userHost PRIVMSG "+testUser+" :ACTION claps hands"; + String rawMessage = + ":" + testUser + "!~" + testUser + "@userHost PRIVMSG " + testUser + " :ACTION claps hands"; Message testMessage = testHandler.new Message(rawMessage); testHandler.parseMessage(testMessage); assertEquals("> claps hands", testMessage.getBody()); } - @Test - public void nickIsHighStyleTest() throws BadLocationException, InterruptedException + @Test(groups = {"Test #002"}) + @Parameters({"channelName"}) + public void noticeMessageParseTest(@Optional("someChannel") String channelName) { - String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG testUser :hello testUser!"; - Message testMessage = testHandler.new Message(rawMessage); - testHandler.parseMessage(testMessage); - StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); - String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] hello testUser!" + Reporter.log("Using @Optional variable channelName: " + channelName); - while(testChannel.messageQueueWorking()) - { - TimeUnit.SECONDS.sleep(1); - } + String rawMessage = ":ChanServ!ChanServ@services.libera.chat NOTICE userName :[#" + channelName + + "] Welcome to #" + channelName + "."; + Message testMessage = testHandler.new Message(rawMessage); - // Should be highStyle because someuser mentioned my nick, testUser - assertEquals("highStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 11, testLine).getAttribute("name")); + assertEquals("#" + channelName, testMessage.getChannel()); + // assertEquals("Welcome to #somechannel.", testMessage.getBody()); } - @Test + + @Test(groups = {"Test #003"}, timeOut = 5000) public void nickIsDefaultStyleTest() throws BadLocationException, InterruptedException { String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG #somechannel :Welcome to somechannel!"; @@ -88,16 +101,17 @@ public void nickIsDefaultStyleTest() throws BadLocationException, InterruptedExc StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] hello world!" - while(testChannel.messageQueueWorking()) + while (testChannel.messageQueueWorking()) { TimeUnit.SECONDS.sleep(1); } // Should be defaultStyle because the user didn't mention testUser and is just a normal message - assertEquals("defaultStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 11, testLine).getAttribute("name")); + assertEquals("defaultStyle", + testChannel.getLineFormatter().getStyleAtPosition(testDoc, 11, testLine).getAttribute("name")); } - @Test + @Test(groups = {"Test #003"}, dependsOnMethods = {"backend.MessageHandlerTests.nickIsDefaultStyleTest"}) public void sendActionMessageChannel() { String rawMessage = "/me claps hands"; @@ -110,12 +124,14 @@ public void sendActionMessageChannel() // TODO Auto-generated catch block e.printStackTrace(); } + + Reporter.log("This test won't run unless the dependant method is included in the test and passed."); } @Test - public void sendActionMessageUser() + public void sendPrivateMessageMessageUser() { - String rawMessage = "/me claps hands"; + String rawMessage = "/msg otheruser hello, did you get this message?"; try { testConnection.sendClientText(rawMessage, "otheruser"); @@ -126,10 +142,11 @@ public void sendActionMessageUser() } } - @Test - public void sendPrivateMessageMessageUser() + @Test(groups = {"Test #004"}, dependsOnMethods = {"backend.MessageHandlerTests.sendPrivateMessageMessageUser"}) + public void sendActionMessageUser() { - String rawMessage = "/msg otheruser hello, did you get this message?"; + Reporter.log("Depends on sendPrivateMessageMessageUser which will be implicitly included in this test group."); + String rawMessage = "/me claps hands"; try { testConnection.sendClientText(rawMessage, "otheruser"); @@ -143,7 +160,8 @@ public void sendPrivateMessageMessageUser() @Test public void noticeMessage2() { - String rawMessage = ":channeluser!channelname@channelname/bot/primary NOTICE myUsername :this is just some notice message directed to this user from the "; + String rawMessage = + ":channeluser!channelname@channelname/bot/primary NOTICE myUsername :this is just some notice message directed to this user from the "; Message testMessage = testHandler.new Message(rawMessage); assertEquals("#channelname", testMessage.getChannel()); @@ -185,69 +203,80 @@ public void testQuitServer() assertEquals(MessageHandler.DisconnectMessage.class, testMessage.getMessageBase().getClass()); } - @Test + @Test(groups = {"Test #005"}, timeOut = 1000) public void testChannelLineLimit() throws BadLocationException, InterruptedException { testGUI.setLimitChannelLines(10); testGUI.setJoinsQuitsMain(false); int channelLinesLimit = testGUI.getLimitChannelLinesCount(); - String channelMessage = ":"+testUser+"!~"+testUser+"@urchatclient PRIVMSG #somechannel :line # "; + String channelMessage = ":" + testUser + "!~" + testUser + "@urchatclient PRIVMSG #somechannel :line # "; - for (int i = 0; i < channelLinesLimit+10; i++) { + for (int i = 0; i < channelLinesLimit + 10; i++) + { Message testMessage = testHandler.new Message(channelMessage + i); testHandler.parseMessage(testMessage); } - while(testChannel.messageQueueWorking()) + while (testChannel.messageQueueWorking()) { TimeUnit.SECONDS.sleep(1); } // for (int i = 0; i < serverLinesLimit+10; i++) { - // Message testMessage = testHandler.new Message(serverMessage + i); - // testHandler.parseMessage(testMessage); + // Message testMessage = testHandler.new Message(serverMessage + i); + // testHandler.parseMessage(testMessage); // } - // int serverLinesCount = testServer.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); - int channelLinesCount = testChannel.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); + // int serverLinesCount = + // testServer.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); + int channelLinesCount = + testChannel.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // " line # 509" - assertTrue("Last line should line # 19 but it was"+testLine, testLine.endsWith("line # 19")); + assertTrue("Last line should line # 19 but it was" + testLine, testLine.endsWith("line # 19")); - assertTrue("First line should be line # 10 but it was "+testChannel.getChannelTextPane().getText().split("\n")[0], testChannel.getChannelTextPane().getText().split("\n")[0].endsWith("line # 10")); + assertTrue( + "First line should be line # 10 but it was " + + testChannel.getChannelTextPane().getText().split("\n")[0], + testChannel.getChannelTextPane().getText().split("\n")[0].endsWith("line # 10")); assertSame("Channel line count should equal the line limit", channelLinesLimit, channelLinesCount - 1); } - @Test + @Test(groups = {"Test #005"}, dependsOnMethods = {"backend.MessageHandlerTests.testChannelLineLimit"} + , description = "This test depends on testChannelLineLimit which should fail due to hitting the timeout") public void testServerLineLimit() throws BadLocationException, InterruptedException { testGUI.setLimitServerLines(10); testGUI.setJoinsQuitsMain(false); int serverLinesLimit = testGUI.getLimitServerLinesCount(); - String serverMessage = ":"+testServer.getName()+" 001 "+testUser+" :line # "; + String serverMessage = ":" + testServer.getName() + " 001 " + testUser + " :line # "; - for (int i = 0; i < serverLinesLimit+10; i++) { + for (int i = 0; i < serverLinesLimit + 10; i++) + { Message testMessage = testHandler.new Message(serverMessage + i); testHandler.parseMessage(testMessage); } - while(testServer.messageQueueWorking()) + while (testServer.messageQueueWorking()) { TimeUnit.SECONDS.sleep(1); } - int serverLinesCount = testServer.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); + int serverLinesCount = + testServer.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); StyledDocument testDoc = testServer.getChannelTextPane().getStyledDocument(); String testLine = testServer.getLineFormatter().getLatestLine(testDoc); // " line # 19" - assertTrue("Last line should line # 19 but it was"+testLine, testLine.endsWith("line # 19")); + assertTrue("Last line should line # 19 but it was" + testLine, testLine.endsWith("line # 19")); - assertTrue("First line should be line # 10 but it was "+testServer.getChannelTextPane().getText().split("\n")[0], testServer.getChannelTextPane().getText().split("\n")[0].endsWith("line # 10")); + assertTrue( + "First line should be line # 10 but it was " + testServer.getChannelTextPane().getText().split("\n")[0], + testServer.getChannelTextPane().getText().split("\n")[0].endsWith("line # 10")); assertSame("Channel line count should equal the line limit", serverLinesLimit, serverLinesCount - 1); } @@ -255,7 +284,8 @@ public void testServerLineLimit() throws BadLocationException, InterruptedExcept public void _emojiMessage() { // test display of emojis in text - String rawMessage = ":sd!~discord@user/sd PRIVMSG #somechannel :02 this should show a flag"; + String rawMessage = + ":sd!~discord@user/sd PRIVMSG #somechannel :02 this should show a flag"; // TODO create this test } @@ -271,14 +301,16 @@ public void urlInMessage() throws BadLocationException, InterruptedException testHandler.parseMessage(testMessage); StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); - while(testChannel.messageQueueWorking()) + while (testChannel.messageQueueWorking()) { TimeUnit.SECONDS.sleep(1); } - String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] https://google.com" + String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] + // https://google.com" // Should be urlStyle, i.e a clickable link - assertEquals("urlStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 19, testLine).getAttribute("name")); + assertEquals("urlStyle", + testChannel.getLineFormatter().getStyleAtPosition(testDoc, 19, testLine).getAttribute("name")); } @Test @@ -292,35 +324,43 @@ public void channelRegex() String regexLine = ""; - while (matcher.find()) { + while (matcher.find()) + { regexLine = matcher.group(1); } assertTrue(regexLine.equalsIgnoreCase("#urchatclient")); } - @Test + @Test(groups = {"Test #005"}) public void channelInMessage() throws BadLocationException, InterruptedException { + Reporter.log("No dependency, this will pass regardless of the failed testChannelLineLimit method."); + // test displaying channel - Message testMessage = testHandler.new Message(":someuser!~someuser@urchatclient PRIVMSG #somechannel :first line"); + Message testMessage = + testHandler.new Message(":someuser!~someuser@urchatclient PRIVMSG #somechannel :first line"); testHandler.parseMessage(testMessage); - String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG #somechannel :Please join #urchatclient and go to https://github.com/matty-r/urChat then go back to #anotherchannel"; + String rawMessage = + ":someuser!~someuser@urchatclient PRIVMSG #somechannel :Please join #urchatclient and go to https://github.com/matty-r/urChat then go back to #anotherchannel"; testMessage = testHandler.new Message(rawMessage); testHandler.parseMessage(testMessage); StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); - while(testChannel.messageQueueWorking()) + while (testChannel.messageQueueWorking()) { TimeUnit.SECONDS.sleep(1); } String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // Should be channel, i.e clickable name which allows you to join the channel - assertEquals("channelStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 33, testLine).getAttribute("name")); - assertEquals("urlStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 58, testLine).getAttribute("name")); - assertEquals("channelStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 110, testLine).getAttribute("name")); + assertEquals("channelStyle", + testChannel.getLineFormatter().getStyleAtPosition(testDoc, 33, testLine).getAttribute("name")); + assertEquals("urlStyle", + testChannel.getLineFormatter().getStyleAtPosition(testDoc, 58, testLine).getAttribute("name")); + assertEquals("channelStyle", + testChannel.getLineFormatter().getStyleAtPosition(testDoc, 110, testLine).getAttribute("name")); } } From 1f4bf40977e7c68a7d5c3e4f2b19c8047221c1c1 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 20 Nov 2023 13:09:29 +1000 Subject: [PATCH 49/78] try with testng.xml --- build/test-build-linux.sh | 2 +- build/testng.xml | 80 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 build/testng.xml diff --git a/build/test-build-linux.sh b/build/test-build-linux.sh index 30033c8..7de45e5 100755 --- a/build/test-build-linux.sh +++ b/build/test-build-linux.sh @@ -49,7 +49,7 @@ cd ../ mkdir -p "report" # run with jacoco agent to build coverage.exec -java -javaagent:lib/jacocoagent.jar=destfile=coverage.exec -cp "urChat.jar:lib/*:urTestRunner.jar" URTestRunner +java -javaagent:lib/jacocoagent.jar=destfile=coverage.exec -cp "urChat.jar:lib/*:urTestRunner.jar" org.testng.TestNG ./build/testng.xml # build html report pointing to the source .java files java -jar lib/jacococli.jar report coverage.exec --classfiles urChat.jar --html report --sourcefiles src/ diff --git a/build/testng.xml b/build/testng.xml new file mode 100644 index 0000000..14dbf23 --- /dev/null +++ b/build/testng.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 6a94cee31770286495ce530e4daeb8703f0584b9 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 20 Nov 2023 16:06:35 +1000 Subject: [PATCH 50/78] Improve the test-build-linux script to include the test libs needed to run the test JAR --- README.md | 15 +++++++++--- build/test-build-linux.sh | 49 ++++++++++++++++++++++++++++----------- build/testng.xml | 3 ++- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7165bc1..788e0fb 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ Contributions If you would like to assist in the development of urChat take a look at the Issues associated with the project. Please let me know if you wish to tackle a certain issue. -Test Dependencies +Test/Code Coverage Dependencies ====== Dependencies required only for running the tests: -Create a **lib** directory with the following files: +Create a **lib/test** directory with the following files: * [Junit 4](https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar) * [Hamcrest Core](https://repo1.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar) @@ -21,7 +21,7 @@ Create a **lib** directory with the following files: * [JCommander](https://repo1.maven.org/maven2/com/beust/jcommander/1.82/jcommander-1.82.jar) * [SLF4J](https://repo1.maven.org/maven2/org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9.jar) -Extract jacocoagent.jar and jacococli.jar into the **lib** directory +Extract jacocoagent.jar and jacococli.jar into the **lib/coverage** directory * [Jacoco](https://search.maven.org/remotecontent?filepath=org/jacoco/jacoco/0.8.11/jacoco-0.8.11.zip) @@ -29,6 +29,15 @@ Usage ====== Ensure you've got Java 17 available on your system, download and run the latest JAR release (https://github.com/matty-r/urChat/releases). If you'd like to try out the Theme functionality, create a 'themes' directory next to the urChat.jar and download the FlatLAF.jar release and place within that directory. The theme can be selected under the client options page. +Test Usage +====== + +Using the testng.xml - must be in the same directory as urchat.jar +* java -cp "urTestRunner.jar" org.testng.TestNG testng.xml + +Without testng.xml +* java -jar urTestRunner.jar + Screenshots ====== diff --git a/build/test-build-linux.sh b/build/test-build-linux.sh index 7de45e5..b6c38aa 100755 --- a/build/test-build-linux.sh +++ b/build/test-build-linux.sh @@ -20,39 +20,60 @@ cp -r "$initial_dir/src/images" "." echo "Main-Class: urChatBasic.frontend.DriverGUI" > ../manifest.txt # Create the JAR file with the manifest and compiled class files, includes the lib and images directory in the created JAR file -jar -cfm "urChat.jar" ../manifest.txt . +jar -cfm "urchat.jar" ../manifest.txt . # Delete all the files not needed to compile the test runner rm -rf "images" rm -rf "urChatBasic" # Copy the lib directory -cp -r "$initial_dir/lib" "." +cp -r "$initial_dir/lib" "$temp_dir/" -# Compile the Java files for the urTestRunner, using the urChat.jar as a source of the lib files -find ../tests -name "*.java" -exec javac -cp "urChat.jar:./lib/*" -d . {} + +# Copy the test libs +cp -r "$temp_dir/lib/test/" "$temp_dir/bin/" -# Move the main.jar back into the temp dir (we don't want it included in the test runner jar) -mv "urChat.jar" ../ +# Compile the Java files for the urTestRunner, using the urchat.jar as a source of the lib files +find ../tests -name "*.java" -exec javac -cp "urchat.jar:test/*" -d . {} + -# Create a manifest file for the test runner +# Extract the test libs to be included in urTestRunner.jar +mkdir -p "$temp_dir/extracted_libs" +cd "$temp_dir/extracted_libs" + +for file in "$temp_dir"/lib/test/*.jar; do + jar xf "$file" +done + +cd "$temp_dir/bin" + +# Move the main.jar back into the temp dir (we don't want it included in urTestRunner) +mv "urchat.jar" "$temp_dir" + +# Delete the test libs +rm -rf "test" + +# Create a manifest file for urTestRunner echo "Main-Class: URTestRunner" > ../testmanifest.txt -echo "Class-Path: urChat.jar ./lib/*" >> ../testmanifest.txt +echo "Class-Path: urchat.jar test/*" >> ../testmanifest.txt -jar -cfm "urTestRunner.jar" ../testmanifest.txt . +# Compile to urTestRunner.jar using the testmanifest.txt, the contents of the current directory (/bin) plus the extracted_libs +jar -cfm "urTestRunner.jar" "$temp_dir/testmanifest.txt" . -C "$temp_dir/extracted_libs/" . -mv "lib" ../ -mv "urTestRunner.jar" ../ +mv "urTestRunner.jar" "$temp_dir" -cd ../ +cd "$temp_dir" mkdir -p "report" # run with jacoco agent to build coverage.exec -java -javaagent:lib/jacocoagent.jar=destfile=coverage.exec -cp "urChat.jar:lib/*:urTestRunner.jar" org.testng.TestNG ./build/testng.xml +java -javaagent:lib/coverage/jacocoagent.jar=destfile=coverage.exec -cp "urchat.jar:urTestRunner.jar" org.testng.TestNG ./build/testng.xml # build html report pointing to the source .java files -java -jar lib/jacococli.jar report coverage.exec --classfiles urChat.jar --html report --sourcefiles src/ +java -jar lib/coverage/jacococli.jar report coverage.exec --classfiles urchat.jar --html report --sourcefiles src/ + +# Move the JARs to the release directory +mkdir -p "$initial_dir/release" +mv "$temp_dir/urchat.jar" "$initial_dir/release" +mv "$temp_dir/urTestRunner.jar" "$initial_dir/release" # Jacoco Output mv "report" "$initial_dir" diff --git a/build/testng.xml b/build/testng.xml index 14dbf23..226e038 100644 --- a/build/testng.xml +++ b/build/testng.xml @@ -2,10 +2,11 @@ - + + From 741cb3e222371a1853d43426132d6f67e7a23798 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 23 Nov 2023 05:36:02 +1000 Subject: [PATCH 51/78] Adjusting tests to use TestNG Asserts --- tests/backend/DialogTests.java | 2 +- tests/backend/MessageHandlerTests.java | 9 ++++----- tests/backend/UserGUITests.java | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/backend/DialogTests.java b/tests/backend/DialogTests.java index ef1b1e7..00275ce 100644 --- a/tests/backend/DialogTests.java +++ b/tests/backend/DialogTests.java @@ -2,12 +2,12 @@ import urChatBasic.frontend.dialogs.MessageDialog; import urChatBasic.frontend.dialogs.YesNoDialog; -import static org.junit.Assert.*; import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.JButton; import javax.swing.JOptionPane; import org.testng.Reporter; import org.testng.annotations.Test; +import static org.testng.AssertJUnit.*; public class DialogTests { diff --git a/tests/backend/MessageHandlerTests.java b/tests/backend/MessageHandlerTests.java index f7be8e5..de42b1f 100644 --- a/tests/backend/MessageHandlerTests.java +++ b/tests/backend/MessageHandlerTests.java @@ -9,9 +9,6 @@ import urChatBasic.frontend.IRCServer; import urChatBasic.frontend.IRCUser; import urChatBasic.frontend.UserGUI; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; @@ -24,6 +21,8 @@ import org.testng.annotations.Optional; import org.testng.annotations.Parameters; import org.testng.annotations.Test; +import static org.testng.AssertJUnit.*; + public class MessageHandlerTests { @@ -203,7 +202,7 @@ public void testQuitServer() assertEquals(MessageHandler.DisconnectMessage.class, testMessage.getMessageBase().getClass()); } - @Test(groups = {"Test #005"}, timeOut = 1000) + @Test(groups = {"Test #005"}) public void testChannelLineLimit() throws BadLocationException, InterruptedException { testGUI.setLimitChannelLines(10); @@ -246,7 +245,7 @@ public void testChannelLineLimit() throws BadLocationException, InterruptedExcep } @Test(groups = {"Test #005"}, dependsOnMethods = {"backend.MessageHandlerTests.testChannelLineLimit"} - , description = "This test depends on testChannelLineLimit which should fail due to hitting the timeout") + , description = "Test Description") public void testServerLineLimit() throws BadLocationException, InterruptedException { testGUI.setLimitServerLines(10); diff --git a/tests/backend/UserGUITests.java b/tests/backend/UserGUITests.java index c01af1c..2e179c0 100644 --- a/tests/backend/UserGUITests.java +++ b/tests/backend/UserGUITests.java @@ -6,8 +6,8 @@ import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import urChatBasic.base.Constants; - -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotEquals; +import static org.testng.AssertJUnit.*; public class UserGUITests { Preferences baseTestPreference; From 6e6cb710c10b5db285654a5c39f67dd70354eb41 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 24 Nov 2023 05:34:31 +1000 Subject: [PATCH 52/78] All styles can now be edited and saved along with your profile --- src/urChatBasic/base/IRCRoomBase.java | 2 +- src/urChatBasic/frontend/LineFormatter.java | 282 ++++++++++++------ src/urChatBasic/frontend/UserGUI.java | 18 +- .../frontend/components/FontPanel.java | 1 + 4 files changed, 193 insertions(+), 110 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index b904641..60811e2 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -521,7 +521,7 @@ public void run() { lineFormatter.formattedDocument(doc, new Date(), fromIRCUser, fromUser, line); - if (lineFormatter.nameStyle.getAttribute("name") == lineFormatter.highStyle() + if (lineFormatter.myStyle.getAttribute("name") == lineFormatter.highStyle() .getAttribute("name")) { callForAttention(); diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 8b441b7..7eb9a1e 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -36,10 +36,10 @@ public class LineFormatter private Font myFont; private IRCServerBase myServer; private Preferences formatterPrefs; - public SimpleAttributeSet defaultStyle; public SimpleAttributeSet timeStyle; - public SimpleAttributeSet nameStyle; public SimpleAttributeSet lineStyle; + public SimpleAttributeSet nickStyle; + public SimpleAttributeSet myStyle; protected UserGUI gui = DriverGUI.gui; public LineFormatter(Font myFont, final IRCServerBase server, Preferences formatterPrefs) @@ -48,107 +48,151 @@ public LineFormatter(Font myFont, final IRCServerBase server, Preferences format this.formatterPrefs = formatterPrefs; - if(null != server) + if (null != server) { myNick = server.getNick(); myServer = server; - } - else + } else { myNick = null; } this.myFont = myFont; - defaultStyle = defaultStyle(); - timeStyle = defaultStyle(); - nameStyle = defaultStyle(); - lineStyle = defaultStyle(); + timeStyle = defaultStyle(null); + lineStyle = defaultStyle(null); + nickStyle = nickStyle(); + myStyle = myStyle(); } public void setFont(StyledDocument doc, Font newFont) { myFont = newFont; - if(doc.getLength() > 0) + if (doc.getLength() > 0) updateStyles(doc, 0); } - public SimpleAttributeSet defaultStyle() + public SimpleAttributeSet loadFontStyle(String name, SimpleAttributeSet loadedStyle) { + + StyleConstants.setFontFamily(loadedStyle, + formatterPrefs.node(name).get("font family", StyleConstants.getFontFamily(loadedStyle).toString())); + + StyleConstants.setFontSize(loadedStyle, + formatterPrefs.node(name).getInt("font size", StyleConstants.getFontSize(loadedStyle))); + + StyleConstants.setBold(loadedStyle, + formatterPrefs.node(name).getBoolean("font bold", StyleConstants.isBold(loadedStyle))); + + StyleConstants.setItalic(loadedStyle, + formatterPrefs.node(name).getBoolean("font italic", StyleConstants.isItalic(loadedStyle))); + + // TODO: Allow for underline and strikethrough + // StyleConstants.setUnderline(defaultStyle, + // formatterPrefs.node(name).getBoolean("font underline", StyleConstants.isUnderline(defaults))); + + // StyleConstants.setStrikeThrough(defaultStyle, + // formatterPrefs.node(name).getBoolean("font strikethrough", StyleConstants.isStrikeThrough(defaults))); + + return loadedStyle; + } + + public SimpleAttributeSet defaultStyle(String name) + { + if (name == null) + name = "defaultStyle"; + SimpleAttributeSet defaultStyle = new SimpleAttributeSet(); - defaultStyle.addAttribute("name", "defaultStyle"); + defaultStyle.addAttribute("name", name); defaultStyle.addAttribute("type", "default"); // get the contrasting colour of the background colour - StyleConstants.setForeground(defaultStyle, - new Color(formatterPrefs.node("defaultStyle").getInt("font foreground", - URColour.getContrastColour(UIManager.getColor("Panel.background")).getRGB() - ))); + StyleConstants.setForeground(defaultStyle, new Color(formatterPrefs.node(name).getInt("font foreground", + URColour.getContrastColour(UIManager.getColor("Panel.background")).getRGB()))); - StyleConstants.setFontFamily(defaultStyle, formatterPrefs.node("defaultStyle").get("font family", myFont.getFamily())); - StyleConstants.setFontSize(defaultStyle, formatterPrefs.node("defaultStyle").getInt("font size", myFont.getSize())); - StyleConstants.setBold(defaultStyle, formatterPrefs.node("defaultStyle").getBoolean("font bold", myFont.isBold())); - StyleConstants.setItalic(defaultStyle, formatterPrefs.node("defaultStyle").getBoolean("font italic", myFont.isItalic())); + StyleConstants.setFontFamily(defaultStyle, myFont.getFamily()); + StyleConstants.setFontSize(defaultStyle, myFont.getSize()); + StyleConstants.setBold(defaultStyle, myFont.isBold()); + StyleConstants.setItalic(defaultStyle, myFont.isItalic()); + + defaultStyle = loadFontStyle(name, defaultStyle); return defaultStyle; } public SimpleAttributeSet lowStyle() { - SimpleAttributeSet tempStyle = defaultStyle(); - tempStyle.addAttribute("name", "lowStyle"); + String name = "lowStyle"; + + SimpleAttributeSet tempStyle = defaultStyle(name); - if(URColour.useDarkColour(UIManager.getColor("Panel.background"))) + if (URColour.useDarkColour(UIManager.getColor("Panel.background"))) { StyleConstants.setForeground(tempStyle, Color.DARK_GRAY); - } else { + } else + { StyleConstants.setForeground(tempStyle, Color.LIGHT_GRAY); } - StyleConstants.setBold(tempStyle, formatterPrefs.node("lowStyle").getBoolean("font bold", StyleConstants.isBold(tempStyle))); + tempStyle = loadFontStyle(name, tempStyle); return tempStyle; } public SimpleAttributeSet mediumStyle() { + String name = "mediumStyle"; + + SimpleAttributeSet tempStyle = defaultStyle(name); - SimpleAttributeSet tempStyle = defaultStyle(); - tempStyle.addAttribute("name", "mediumStyle"); - // StyleConstants.setBackground(tempStyle, Color.YELLOW); + tempStyle = loadFontStyle(name, tempStyle); return tempStyle; } public SimpleAttributeSet highStyle() { - SimpleAttributeSet tempStyle = defaultStyle(); - tempStyle.addAttribute("name", "highStyle"); + String name = "highStyle"; + + SimpleAttributeSet tempStyle = defaultStyle(name); + + StyleConstants.setBackground(tempStyle, UIManager.getColor("CheckBoxMenuItem.selectionBackground")); // TODO: + // Get + // highlight + // colour? + StyleConstants.setForeground(tempStyle, + URColour.getContrastColour(UIManager.getColor("CheckBoxMenuItem.selectionBackground"))); - StyleConstants.setBackground(tempStyle, UIManager.getColor("CheckBoxMenuItem.selectionBackground")); // TODO: Get highlight colour? - StyleConstants.setForeground(tempStyle, URColour.getContrastColour(UIManager.getColor("CheckBoxMenuItem.selectionBackground"))); StyleConstants.setBold(tempStyle, true); StyleConstants.setItalic(tempStyle, true); + tempStyle = loadFontStyle(name, tempStyle); + return tempStyle; } public SimpleAttributeSet urlStyle() { - SimpleAttributeSet tempStyle = defaultStyle(); + String name = "urlStyle"; + + SimpleAttributeSet tempStyle = defaultStyle(name); - tempStyle.addAttribute("name", "urlStyle"); tempStyle.addAttribute("type", "url"); + StyleConstants.setForeground(tempStyle, UIManager.getColor("CheckBoxMenuItem.selectionBackground")); StyleConstants.setUnderline(tempStyle, true); + tempStyle = loadFontStyle(name, tempStyle); + return tempStyle; } public SimpleAttributeSet channelStyle() { + String name = "channelStyle"; + SimpleAttributeSet tempStyle = urlStyle(); - tempStyle.addAttribute("name", "channelStyle"); + tempStyle.addAttribute("name", name); tempStyle.addAttribute("type", "channel"); return tempStyle; @@ -156,14 +200,34 @@ public SimpleAttributeSet channelStyle() public SimpleAttributeSet myStyle() { - SimpleAttributeSet tempStyle = defaultStyle(); - tempStyle.addAttribute("name", "myStyle"); + String name = "myStyle"; + + SimpleAttributeSet tempStyle = defaultStyle(name); + tempStyle.addAttribute("type", "myNick"); + // StyleConstants.setForeground(tempStyle, Color.GREEN); - StyleConstants.setForeground(tempStyle, URColour.getInvertedColour(UIManager.getColor("CheckBoxMenuItem.selectionBackground"))); + StyleConstants.setForeground(tempStyle, + URColour.getInvertedColour(UIManager.getColor("CheckBoxMenuItem.selectionBackground"))); StyleConstants.setBold(tempStyle, true); StyleConstants.setUnderline(tempStyle, true); + tempStyle = loadFontStyle(name, tempStyle); + + return tempStyle; + } + + public SimpleAttributeSet nickStyle() + { + String name = "nickStyle"; + + SimpleAttributeSet tempStyle = defaultStyle(name); + tempStyle.addAttribute("type", "nick"); + + StyleConstants.setUnderline(tempStyle, true); + + tempStyle = loadFontStyle(name, tempStyle); + return tempStyle; } @@ -183,7 +247,7 @@ public class ClickableText extends AbstractAction this.textLink = textLink; this.attributeSet = attributeSet; - if(fromUser != null) + if (fromUser != null) { this.fromUser = fromUser; } @@ -199,34 +263,41 @@ public void execute() { if (!textLink.isEmpty() && attributeSet.getAttribute("type").equals("url")) { - try { + try + { AtomicBoolean doOpenLink = new AtomicBoolean(false); - YesNoDialog confirmOpenLink = new YesNoDialog("Are you sure you want to open "+textLink+"?", "Open Link", - JOptionPane.QUESTION_MESSAGE, e -> doOpenLink.set(e.getActionCommand().equalsIgnoreCase("Yes"))); + YesNoDialog confirmOpenLink = new YesNoDialog("Are you sure you want to open " + textLink + "?", + "Open Link", JOptionPane.QUESTION_MESSAGE, + e -> doOpenLink.set(e.getActionCommand().equalsIgnoreCase("Yes"))); confirmOpenLink.setVisible(true); - if(doOpenLink.get()) + if (doOpenLink.get()) Desktop.getDesktop().browse(new URL(textLink).toURI()); - } catch (Exception e) { + } catch (Exception e) + { e.printStackTrace(); } - } else if(!textLink.isEmpty() && attributeSet.getAttribute("type").equals("channel")) + } else if (!textLink.isEmpty() && attributeSet.getAttribute("type").equals("channel")) { - try { + try + { AtomicBoolean doJoinChannel = new AtomicBoolean(false); - YesNoDialog confirmOpenLink = new YesNoDialog("Are you sure you want to join channel "+textLink+"?", "Join Channel", - JOptionPane.QUESTION_MESSAGE, e -> doJoinChannel.set(e.getActionCommand().equalsIgnoreCase("Yes"))); + YesNoDialog confirmOpenLink = + new YesNoDialog("Are you sure you want to join channel " + textLink + "?", "Join Channel", + JOptionPane.QUESTION_MESSAGE, + e -> doJoinChannel.set(e.getActionCommand().equalsIgnoreCase("Yes"))); confirmOpenLink.setVisible(true); - if(doJoinChannel.get()) + if (doJoinChannel.get()) { myServer.sendClientText("/join " + textLink, ""); } - } catch (Exception e) { + } catch (Exception e) + { e.printStackTrace(); } } @@ -234,7 +305,7 @@ public void execute() public JPopupMenu rightClickMenu() { - if(attributeSet.getAttribute("type").equals("IRCUser")) + if (attributeSet.getAttribute("type").equals("IRCUser")) { fromUser.createPopUp(); return fromUser.myMenu; @@ -253,7 +324,8 @@ public void actionPerformed(ActionEvent e) } // Inserts the string at the position - private void insertString(StyledDocument doc, String insertedString, SimpleAttributeSet style, int position) throws BadLocationException + private void insertString(StyledDocument doc, String insertedString, SimpleAttributeSet style, int position) + throws BadLocationException { // remove the existing attributes style.removeAttribute("styleStart"); @@ -266,7 +338,8 @@ private void insertString(StyledDocument doc, String insertedString, SimpleAttri } // Adds the string (with all needed attributes) to the end of the document - private void appendString(StyledDocument doc, String insertedString, SimpleAttributeSet style) throws BadLocationException + private void appendString(StyledDocument doc, String insertedString, SimpleAttributeSet style) + throws BadLocationException { int position = doc.getLength(); @@ -275,11 +348,14 @@ private void appendString(StyledDocument doc, String insertedString, SimpleAttri private SimpleAttributeSet getStyle(String styleName) { - switch (styleName) { + switch (styleName) + { case "mediumStyle": return mediumStyle(); case "highStyle": return highStyle(); + case "nickStyle": + return nickStyle(); case "myStyle": return myStyle(); case "lowStyle": @@ -289,7 +365,7 @@ private SimpleAttributeSet getStyle(String styleName) case "channelStyle": return channelStyle(); default: - return defaultStyle(); + return defaultStyle(null); } } @@ -304,8 +380,8 @@ public Font getStyleAsFont(String styleName) if (StyleConstants.isItalic(fontStyle)) savedFontBoldItalic |= Font.ITALIC; - Font styleFont = new Font(StyleConstants.getFontFamily(fontStyle), - savedFontBoldItalic, StyleConstants.getFontSize(fontStyle)); + Font styleFont = new Font(StyleConstants.getFontFamily(fontStyle), savedFontBoldItalic, + StyleConstants.getFontSize(fontStyle)); return styleFont; } @@ -320,8 +396,10 @@ public void updateStyles(StyledDocument doc, int startPosition) SimpleAttributeSet matchingStyle = getStyle(styleName); - // TODO: Update the time format. Check if there is a timeStyle already, if there is then remove it from the line - // and insert the new timeStyle/Format. Otherwise we just need to insert it. The first character/style will have + // TODO: Update the time format. Check if there is a timeStyle already, if there is then remove it + // from the line + // and insert the new timeStyle/Format. Otherwise we just need to insert it. The first + // character/style will have // the 'date' attribute of when the line was added. boolean isDateStyle = false; @@ -334,18 +412,19 @@ public void updateStyles(StyledDocument doc, int startPosition) String newTimeString = UserGUI.getTimeLineString(lineDate) + " "; boolean hasTime = false; - if (null != textStyle.getAttribute("type") && textStyle.getAttribute("type").toString().equalsIgnoreCase("time")) + if (null != textStyle.getAttribute("type") + && textStyle.getAttribute("type").toString().equalsIgnoreCase("time")) { hasTime = true; doc.remove(styleStart, styleLength); } - if(gui.isTimeStampsEnabled()) + if (gui.isTimeStampsEnabled()) { textStyle.removeAttribute("date"); textStyle.removeAttribute("time"); - if(!hasTime) + if (!hasTime) doc.setCharacterAttributes(styleStart, styleLength, textStyle, true); SimpleAttributeSet timeStyle = getStyle(styleName); @@ -353,8 +432,9 @@ public void updateStyles(StyledDocument doc, int startPosition) timeStyle.addAttribute("type", "time"); insertString(doc, newTimeString, timeStyle, styleStart); styleLength = newTimeString.length(); - } else { - if(hasTime) + } else + { + if (hasTime) { textStyle = new SimpleAttributeSet(doc.getCharacterElement(startPosition).getAttributes()); @@ -376,32 +456,32 @@ public void updateStyles(StyledDocument doc, int startPosition) // Copy the attributes, but only if they aren't already set Iterator attributeIterator = textStyle.getAttributeNames().asIterator(); - while(attributeIterator.hasNext()) + while (attributeIterator.hasNext()) { String nextAttributeName = attributeIterator.next().toString(); - if(matchingStyle.getAttribute(nextAttributeName) == null) + if (matchingStyle.getAttribute(nextAttributeName) == null) { Iterator matchingIterator = matchingStyle.getAttributeNames().asIterator(); boolean needsToBeSet = true; - while(matchingIterator.hasNext()) + while (matchingIterator.hasNext()) { - if(matchingIterator.next().toString().equalsIgnoreCase(nextAttributeName)) + if (matchingIterator.next().toString().equalsIgnoreCase(nextAttributeName)) { needsToBeSet = false; break; } } - if(needsToBeSet) + if (needsToBeSet) matchingStyle.addAttribute(nextAttributeName, textStyle.getAttribute(nextAttributeName)); } } - if(!isDateStyle) + if (!isDateStyle) doc.setCharacterAttributes(styleStart, styleLength, matchingStyle, true); - if((styleStart + styleLength) < doc.getLength()) + if ((styleStart + styleLength) < doc.getLength()) updateStyles(doc, (styleStart + styleLength)); } @@ -412,15 +492,15 @@ public String getLatestLine(StyledDocument doc) throws BadLocationException String finalLine = ""; - while(finalLine.isEmpty()) + while (finalLine.isEmpty()) { - if(lines < 0) + if (lines < 0) break; - Element line = root.getElement( lines-- ); + Element line = root.getElement(lines--); - if(null == line) + if (null == line) continue; int start = line.getStartOffset(); @@ -441,14 +521,14 @@ private int getLinePosition(StyledDocument doc, String targetLine) throws BadLoc { Element line = root.getElement(i); - if(null == line) + if (null == line) continue; int start = line.getStartOffset(); int end = line.getEndOffset(); String text = doc.getText(start, end - start); - if(text.trim().equals(targetLine.trim())) + if (text.trim().equals(targetLine.trim())) { return start; } @@ -457,9 +537,10 @@ private int getLinePosition(StyledDocument doc, String targetLine) throws BadLoc return 0; } - public SimpleAttributeSet getStyleAtPosition(StyledDocument doc, int position, String relativeLine) throws BadLocationException + public SimpleAttributeSet getStyleAtPosition(StyledDocument doc, int position, String relativeLine) + throws BadLocationException { - if(!relativeLine.isBlank()) + if (!relativeLine.isBlank()) position = position + getLinePosition(doc, relativeLine); AttributeSet textStyle = doc.getCharacterElement(position).getAttributes(); @@ -467,7 +548,8 @@ public SimpleAttributeSet getStyleAtPosition(StyledDocument doc, int position, S return new SimpleAttributeSet(textStyle); } - private void parseClickableText(StyledDocument doc, IRCUser fromUser, String line, SimpleAttributeSet defaultStyle) throws BadLocationException + private void parseClickableText(StyledDocument doc, IRCUser fromUser, String line, SimpleAttributeSet defaultStyle) + throws BadLocationException { HashMap regexStrings = new HashMap<>(); regexStrings.put(Constants.URL_REGEX, urlStyle()); @@ -477,7 +559,8 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin ArrayList clickableLines = new ArrayList(); - for (Map.Entry entry : regexStrings.entrySet()) { + for (Map.Entry entry : regexStrings.entrySet()) + { String regex = entry.getKey(); @@ -485,7 +568,8 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin Matcher matcher = pattern.matcher(line); // do stuff for each match - while (matcher.find()) { + while (matcher.find()) + { SimpleAttributeSet linkStyle = getStyle(entry.getValue().getAttribute("name").toString()); String clickableLine = matcher.group(1); linkStyle.addAttribute("clickableText", new ClickableText(clickableLine, linkStyle, fromUser)); @@ -519,7 +603,7 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin int nextLineLength = Integer.parseInt(nextLine.getAttribute("styleLength").toString()); // Append the string that comes before the next clickable text - appendString(doc, remainingLine.substring(0, nextLineStart- offset), defaultStyle); + appendString(doc, remainingLine.substring(0, nextLineStart - offset), defaultStyle); appendString(doc, nextLine.getAttribute("clickableText").toString(), nextLine); @@ -544,21 +628,22 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse if (fromUser != null && null != myNick && myNick.equals(fromUser.toString())) { - nameStyle = this.myStyle(); + nickStyle = myStyle(); } else { if (null != myNick && line.indexOf(myNick) > -1) - nameStyle = highStyle(); + nickStyle = highStyle(); else - nameStyle = defaultStyle(); + nickStyle = nickStyle(); } if (fromUser == null && fromString.equals(Constants.EVENT_USER)) { - nameStyle = lowStyle(); + nickStyle = lowStyle(); lineStyle = lowStyle(); - } else { - lineStyle = defaultStyle(); + } else + { + lineStyle = defaultStyle(null); } timeStyle = lineStyle; @@ -568,7 +653,7 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse // doc.insertString(doc.getLength(), timeLine, timeStyle); // if(null != timeLine && !timeLine.isBlank()) - if(!timeLine.isBlank() && gui.isTimeStampsEnabled()) + if (!timeLine.isBlank() && gui.isTimeStampsEnabled()) { // add the date to the end of the string to preserve the timestamp of the line // when updating styles @@ -578,23 +663,26 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse appendString(doc, timeLine + " ", timeStyle); timeStyle.removeAttribute("type"); lineStyle.removeAttribute("date"); - } else { + } else + { lineStyle.addAttribute("date", lineDate); } appendString(doc, "<", lineStyle); lineStyle.removeAttribute("date"); - if(fromUser != null) + if (fromUser != null) { - SimpleAttributeSet clickableNameStyle = nameStyle; + SimpleAttributeSet clickableNameStyle = nickStyle; clickableNameStyle.addAttribute("type", "IRCUser"); - clickableNameStyle.addAttribute("clickableText", new ClickableText(fromUser.toString(), nameStyle, fromUser)); + clickableNameStyle.addAttribute("clickableText", + new ClickableText(fromUser.toString(), nickStyle, fromUser)); // doc.insertString(doc.getLength(), fromUser.toString(), clickableNameStyle); appendString(doc, fromUser.toString(), clickableNameStyle); - } else { - appendString(doc, fromString, nameStyle); + } else + { + appendString(doc, fromString, nickStyle); } appendString(doc, ">", lineStyle); @@ -603,7 +691,7 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse // appendString(doc, " "+line, lineStyle); // parse the outputted line for clickable text - parseClickableText(doc, fromUser, " "+line, lineStyle); + parseClickableText(doc, fromUser, " " + line, lineStyle); appendString(doc, System.getProperty("line.separator"), lineStyle); } catch (BadLocationException e) diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 7d2b36c..8bfc1d1 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -16,7 +16,6 @@ import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.event.*; import javax.swing.text.AttributeSet; -import javax.swing.text.BadLocationException; import javax.swing.text.Element; import javax.swing.text.StyledDocument; import urChatBasic.backend.utils.URUncaughtExceptionHandler; @@ -79,12 +78,6 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase // Appearance Panel private FontPanel clientFontPanel; private static final JTextField timeStampField = new JTextField(); - private static final JLabel timeStampFontLabel = new JLabel("Timestamp Font"); - private static final JButton otherNickFontLabel = new JButton("Other Nick Font"); - private static final JButton userNickFontLabel = new JButton("My Nick Font"); - private static final JButton lowStyleFontLabel = new JButton("Low Priority Text Font"); - private static final JButton mediumStyleFontLabel = new JButton("Medium Priority Text Font"); - private static final JButton highStyleFontLabel = new JButton("High Priority Text Font"); private static final JTextPane previewTextArea = new JTextPane(); private static final JScrollPane previewTextScroll = new JScrollPane(previewTextArea); private static final JLabel styleLabel = new JLabel("Mouse over text to view style, right-click to edit."); @@ -927,10 +920,11 @@ class PreviewClickListener extends MouseInputAdapter public void mouseClicked(MouseEvent e) { StyledDocument doc = previewTextArea.getStyledDocument(); - Element ele = doc.getCharacterElement(previewTextArea.viewToModel2D((e.getPoint()))); - AttributeSet as = ele.getAttributes(); - ClickableText isClickableText = (ClickableText) as.getAttribute("clickableText"); - if (SwingUtilities.isRightMouseButton(e)) + Element wordElement = doc.getCharacterElement(previewTextArea.viewToModel2D((e.getPoint()))); + AttributeSet wordAttributeSet = wordElement.getAttributes(); + ClickableText isClickableText = (ClickableText) wordAttributeSet.getAttribute("clickableText"); + + if (SwingUtilities.isRightMouseButton(e) && wordAttributeSet.getAttribute("name") != null) { String styleName = styleLabel.getText(); FontDialog styleFontDialog = new FontDialog(styleName, previewLineFormatter.getStyleAsFont(styleName), getProfilePath().node(styleName)); @@ -984,7 +978,7 @@ public void mouseMoved(MouseEvent e) AttributeSet wordAttributeSet = wordElement.getAttributes(); ClickableText isClickableText = (ClickableText) wordAttributeSet.getAttribute("clickableText"); - if(null != wordAttributeSet.getAttribute("name")) + if(wordAttributeSet.getAttribute("name") != null) styleLabel.setText(wordAttributeSet.getAttribute("name").toString()); else styleLabel.setText("Mouse over text to view style, right-click to edit."); diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index f50084a..1403920 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -63,6 +63,7 @@ public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) setDefaultFont(defaultFont); loadFont(); + // TODO: Implement underline and strikethrough, plus colour selection MAIN_PANEL.add(FONT_COMBO_BOX); MAIN_PANEL.add(SIZES_COMBO_BOX); MAIN_PANEL.add(TEXT_PREVIEW); From 7ac8e96b58880d95102d5cb19a185d6048694d90 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 24 Nov 2023 06:25:07 +1000 Subject: [PATCH 53/78] Fixes up the reset font option in the FontPanel --- src/urChatBasic/frontend/LineFormatter.java | 6 ----- src/urChatBasic/frontend/UserGUI.java | 26 +++++++++---------- .../frontend/components/FontPanel.java | 15 ++++++++--- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 7eb9a1e..228326b 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -396,12 +396,6 @@ public void updateStyles(StyledDocument doc, int startPosition) SimpleAttributeSet matchingStyle = getStyle(styleName); - // TODO: Update the time format. Check if there is a timeStyle already, if there is then remove it - // from the line - // and insert the new timeStyle/Format. Otherwise we just need to insert it. The first - // character/style will have - // the 'date' attribute of when the line was added. - boolean isDateStyle = false; if (null != gui && null != textStyle.getAttribute("date")) { diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 8bfc1d1..9f002a3 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -927,7 +927,7 @@ public void mouseClicked(MouseEvent e) if (SwingUtilities.isRightMouseButton(e) && wordAttributeSet.getAttribute("name") != null) { String styleName = styleLabel.getText(); - FontDialog styleFontDialog = new FontDialog(styleName, previewLineFormatter.getStyleAsFont(styleName), getProfilePath().node(styleName)); + FontDialog styleFontDialog = new FontDialog(styleName, clientFontPanel.getFont(), getProfilePath().node(styleName)); styleFontDialog.addSaveListener(new ActionListener() { @@ -944,21 +944,21 @@ public void actionPerformed(ActionEvent arg0) { }); - styleFontDialog.addResetListener(new ActionListener() { + // styleFontDialog.addResetListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - try { - getProfilePath().node(styleName).removeNode(); - } catch (BackingStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + // @Override + // public void actionPerformed(ActionEvent arg0) { + // try { + // getProfilePath().node(styleName).removeNode(); + // } catch (BackingStoreException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } - previewLineFormatter.updateStyles(doc, 0); - } + // previewLineFormatter.updateStyles(doc, 0); + // } - }); + // }); styleFontDialog.setVisible(true); diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 1403920..f1a0e70 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -12,6 +12,7 @@ import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.List; +import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.swing.*; import urChatBasic.base.Constants; @@ -118,10 +119,16 @@ public void setDefaultFont(Font f) // The default font for a channel is the Global Font, the default font // the UserGUI is Constants.DEFAULT_FONT public void resetFont() { - settingsPath.remove(Constants.KEY_FONT_BOLD); - settingsPath.remove(Constants.KEY_FONT_ITALIC); - settingsPath.remove(Constants.KEY_FONT_SIZE); - settingsPath.remove(Constants.KEY_FONT_FAMILY); + try + { + for (String key : settingsPath.keys()) { + settingsPath.remove(key); + } + } catch (BackingStoreException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } loadFont(); } From 8425806c44aee6e145fd78934b4757f55274870f Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 27 Nov 2023 06:27:47 +1000 Subject: [PATCH 54/78] Adding prelim colour dialog/panel, refactored FontPanel --- .../frontend/components/ColourPanel.java | 74 +++++++++++++++ .../frontend/components/FontPanel.java | 90 +++++++++++-------- .../frontend/dialogs/ColourDialog.java | 60 +++++++++++++ 3 files changed, 188 insertions(+), 36 deletions(-) create mode 100644 src/urChatBasic/frontend/components/ColourPanel.java create mode 100644 src/urChatBasic/frontend/dialogs/ColourDialog.java diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java new file mode 100644 index 0000000..bf09c02 --- /dev/null +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -0,0 +1,74 @@ +package urChatBasic.frontend.components; + +import java.awt.*; +import javax.swing.*; +import javax.swing.event.*; + +/* ColorChooserDemo.java requires no other files. */ +public class ColourPanel extends JPanel + implements ChangeListener { + + protected JColorChooser tcc; + protected JLabel banner; + + public ColourPanel() { + super(new BorderLayout()); + + //Set up the banner at the top of the window + banner = new JLabel("Welcome to the Tutorial Zone!", + JLabel.CENTER); + banner.setForeground(Color.yellow); + banner.setBackground(Color.blue); + banner.setOpaque(true); + banner.setFont(new Font("SansSerif", Font.BOLD, 24)); + banner.setPreferredSize(new Dimension(100, 65)); + + JPanel bannerPanel = new JPanel(new BorderLayout()); + bannerPanel.add(banner, BorderLayout.CENTER); + bannerPanel.setBorder(BorderFactory.createTitledBorder("Banner")); + + //Set up color chooser for setting text color + tcc = new JColorChooser(banner.getForeground()); + tcc.getSelectionModel().addChangeListener(this); + tcc.setBorder(BorderFactory.createTitledBorder( + "Choose Text Color")); + + add(bannerPanel, BorderLayout.CENTER); + add(tcc, BorderLayout.PAGE_END); + } + + public void stateChanged(ChangeEvent e) { + Color newColor = tcc.getColor(); + banner.setForeground(newColor); + } + + /** + * Create the GUI and show it. For thread safety, + * this method should be invoked from the + * event-dispatching thread. + */ + private static void createAndShowGUI() { + //Create and set up the window. + JFrame frame = new JFrame("ColorChooserDemo"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + //Create and set up the content pane. + JComponent newContentPane = new ColourPanel(); + newContentPane.setOpaque(true); //content panes must be opaque + frame.setContentPane(newContentPane); + + //Display the window. + frame.pack(); + frame.setVisible(true); + } + + public static void main(String[] args) { + //Schedule a job for the event-dispatching thread: + //creating and showing this application's GUI. + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void run() { + createAndShowGUI(); + } + }); + } +} diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index f1a0e70..ed856d5 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -1,5 +1,6 @@ package urChatBasic.frontend.components; +import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.GraphicsEnvironment; @@ -29,16 +30,14 @@ public class FontPanel extends JPanel private final Integer[] FONT_SIZES = {8, 10, 11, 12, 14, 16, 18, 20, 24, 30, 36, 40, 60, 72}; private final JComboBox SIZES_COMBO_BOX = new JComboBox<>(FONT_SIZES); private final JCheckBox MAKE_BOLD = new JCheckBox("BOLD"); + private final JCheckBox MAKE_UNDERLINE = new JCheckBox("UNDERLINE"); private final JCheckBox MAKE_ITALIC = new JCheckBox("ITALIC"); - private final JButton RESET_BUTTON = new JButton("Reset Font"); - private final JButton SAVE_BUTTON = new JButton("Save Font"); + private final JButton RESET_BUTTON = new JButton("Reset"); + private final JButton SAVE_BUTTON = new JButton("Save"); + private final JButton COLOUR_BUTTON = new JButton("Colour"); // private String fontType = "New Font:"; // private JLabel fontTypeLabel = new JLabel("New Font:"); - // private final JPanel TITLE_PANEL = new JPanel(new GridLayout(1,1)); - private final JPanel BUTTON_PANEL = new JPanel(new GridLayout(1, 2)); - private final JPanel MAIN_PANEL = new JPanel(new GridLayout(2, 3)); private Font defaultFont; - // private final JButton CANCEL_BUTTON = new JButton("Cancel"); // TODO: Add colour picker for foreground and background private List actionListeners = new ArrayList<>(); @@ -47,38 +46,14 @@ public class FontPanel extends JPanel public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) { - // setPreferredSize(new Dimension(0, 100)); - // fontTypeLabel = new JLabel(fontName); setLayout(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - // c.fill = GridBagConstraints.HORIZONTAL; - - // c.gridx = 0; - // c.gridy = 0; - - // TITLE_PANEL.add(fontTypeLabel); - // add(TITLE_PANEL, c); - setSettingsPath(settingsPath); setDefaultFont(defaultFont); loadFont(); - // TODO: Implement underline and strikethrough, plus colour selection - MAIN_PANEL.add(FONT_COMBO_BOX); - MAIN_PANEL.add(SIZES_COMBO_BOX); - MAIN_PANEL.add(TEXT_PREVIEW); - MAIN_PANEL.add(MAKE_BOLD); - MAIN_PANEL.add(MAKE_ITALIC); - - BUTTON_PANEL.add(RESET_BUTTON); - BUTTON_PANEL.add(SAVE_BUTTON); - - MAIN_PANEL.add(BUTTON_PANEL); - - RESET_BUTTON.addActionListener(new ResetListener()); - // SAVE_BUTTON.addActionListener(new SaveListener()); + addActionListener(SAVE_BUTTON, new SaveListener()); FONT_COMBO_BOX.addItemListener(new FontSelectionChange()); SIZES_COMBO_BOX.addItemListener(new FontSelectionChange()); @@ -86,17 +61,60 @@ public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) MAKE_ITALIC.addActionListener(new CheckListener()); // Reset the GridBagConstraints for MAIN_PANEL + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LINE_START; // Align components to the left + // Set constraints for MAIN_PANEL + // c.gridwidth = 6; // Assuming you want MAIN_PANEL to span three columns + // c.weightx = 1.0; + // c.weighty = 1.0; + + // First Row + c.gridx = 0; + c.gridy = 0; + c.gridwidth = 1; + c.weightx = 1.0; + add(FONT_COMBO_BOX, c); + + c.gridx = 1; + c.gridy = 0; + c.gridwidth = 1; + add(SIZES_COMBO_BOX, c); + + c.gridx = 2; + c.gridy = 0; + add(COLOUR_BUTTON, c); + + c.gridx = 3; + c.gridy = 0; + add(RESET_BUTTON, c); + + c.gridx = 4; + c.gridy = 0; + add(SAVE_BUTTON, c); + + // Second Row c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LINE_START; // Align components to the left c.gridx = 0; c.gridy = 1; + c.gridwidth = 3; // Assuming TEXT_PREVIEW spans three columns + add(TEXT_PREVIEW, c); - // Set constraints for MAIN_PANEL - c.gridwidth = 1; // Assuming you want MAIN_PANEL to span two columns - c.weightx = 1.0; - c.weighty = 1.0; + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 1; + add(MAKE_BOLD, c); - add(MAIN_PANEL, c); + c.gridx = 2; + c.gridy = 1; + add(MAKE_ITALIC, c); + + c.gridx = 3; + c.gridy = 1; + c.gridwidth = 2; + add(MAKE_UNDERLINE, c); } public JButton getSaveButton() diff --git a/src/urChatBasic/frontend/dialogs/ColourDialog.java b/src/urChatBasic/frontend/dialogs/ColourDialog.java new file mode 100644 index 0000000..67945d3 --- /dev/null +++ b/src/urChatBasic/frontend/dialogs/ColourDialog.java @@ -0,0 +1,60 @@ +package urChatBasic.frontend.dialogs; + +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.prefs.Preferences; +import urChatBasic.base.DialogBase; +import urChatBasic.frontend.DriverGUI; +import urChatBasic.frontend.components.ColourPanel; + +public class ColourDialog extends DialogBase +{ + private ColourPanel colourPanel; + + public ColourDialog(String title, Preferences settingsPath) + { + super(DriverGUI.frame, title, true); + initColourDialog(settingsPath); + } + + public void initColourDialog(Preferences settingsPath) + { + setSize(600, 600); + setResizable(false); + setMaximumSize(new Dimension(600, 600)); + setLocationRelativeTo(super.getParent()); + + colourPanel = new ColourPanel(); + + add(colourPanel); + } + + // @Override + // public void setVisible(boolean b) + // { + // fontPanel.loadFont(); + // super.setVisible(b); + // } + + // public void addSaveListener(ActionListener newActionListener) + // { + // // fontPanel.getSaveButton().addActionListener(newActionListener); + // fontPanel.addActionListener(fontPanel.getSaveButton(), newActionListener); + // } + + // public void addResetListener(ActionListener newActionListener) + // { + // fontPanel.getResetButton().addActionListener(newActionListener); + // } + + public class ShowColourDialog implements ActionListener + { + @Override + public void actionPerformed(ActionEvent arg0) + { + // fontPanel.loadFont(); + ColourDialog.this.setVisible(true); + } + } +} From 62ec1ea77d8665101afd3889810c97817cd830e4 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 27 Nov 2023 07:56:35 +1000 Subject: [PATCH 55/78] Show colour dialog when pressing the colour button --- .../frontend/components/ColourPanel.java | 18 +----------------- .../frontend/components/FontPanel.java | 16 ++++++++++++++-- .../frontend/dialogs/ColourDialog.java | 12 +++++++----- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index bf09c02..d712dac 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -9,37 +9,21 @@ public class ColourPanel extends JPanel implements ChangeListener { protected JColorChooser tcc; - protected JLabel banner; public ColourPanel() { super(new BorderLayout()); - //Set up the banner at the top of the window - banner = new JLabel("Welcome to the Tutorial Zone!", - JLabel.CENTER); - banner.setForeground(Color.yellow); - banner.setBackground(Color.blue); - banner.setOpaque(true); - banner.setFont(new Font("SansSerif", Font.BOLD, 24)); - banner.setPreferredSize(new Dimension(100, 65)); - - JPanel bannerPanel = new JPanel(new BorderLayout()); - bannerPanel.add(banner, BorderLayout.CENTER); - bannerPanel.setBorder(BorderFactory.createTitledBorder("Banner")); - //Set up color chooser for setting text color - tcc = new JColorChooser(banner.getForeground()); + tcc = new JColorChooser(getForeground()); tcc.getSelectionModel().addChangeListener(this); tcc.setBorder(BorderFactory.createTitledBorder( "Choose Text Color")); - add(bannerPanel, BorderLayout.CENTER); add(tcc, BorderLayout.PAGE_END); } public void stateChanged(ChangeEvent e) { Color newColor = tcc.getColor(); - banner.setForeground(newColor); } /** diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index ed856d5..c3957a7 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -17,6 +17,7 @@ import java.util.prefs.Preferences; import javax.swing.*; import urChatBasic.base.Constants; +import urChatBasic.frontend.dialogs.ColourDialog; public class FontPanel extends JPanel { @@ -35,6 +36,7 @@ public class FontPanel extends JPanel private final JButton RESET_BUTTON = new JButton("Reset"); private final JButton SAVE_BUTTON = new JButton("Save"); private final JButton COLOUR_BUTTON = new JButton("Colour"); + protected ColourDialog colourDialog = null; // private String fontType = "New Font:"; // private JLabel fontTypeLabel = new JLabel("New Font:"); private Font defaultFont; @@ -47,13 +49,23 @@ public class FontPanel extends JPanel public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) { setLayout(new GridBagLayout()); - setSettingsPath(settingsPath); setDefaultFont(defaultFont); loadFont(); RESET_BUTTON.addActionListener(new ResetListener()); - + COLOUR_BUTTON.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent arg0) + { + if(colourDialog == null) + colourDialog = new ColourDialog(fontName, settingsPath); + + colourDialog.setVisible(true); + } + }); + addActionListener(SAVE_BUTTON, new SaveListener()); FONT_COMBO_BOX.addItemListener(new FontSelectionChange()); SIZES_COMBO_BOX.addItemListener(new FontSelectionChange()); diff --git a/src/urChatBasic/frontend/dialogs/ColourDialog.java b/src/urChatBasic/frontend/dialogs/ColourDialog.java index 67945d3..aedbe3e 100644 --- a/src/urChatBasic/frontend/dialogs/ColourDialog.java +++ b/src/urChatBasic/frontend/dialogs/ColourDialog.java @@ -20,14 +20,16 @@ public ColourDialog(String title, Preferences settingsPath) public void initColourDialog(Preferences settingsPath) { - setSize(600, 600); - setResizable(false); - setMaximumSize(new Dimension(600, 600)); - setLocationRelativeTo(super.getParent()); - colourPanel = new ColourPanel(); add(colourPanel); + setContentPane(colourPanel); + pack(); + + // setSize(600, 600); + setResizable(false); + // setMaximumSize(new Dimension(600, 600)); + setLocationRelativeTo(super.getParent()); } // @Override From 7d1157c9498f71529f2038ec3a73f3b5a059df6e Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 29 Nov 2023 06:25:22 +1000 Subject: [PATCH 56/78] Added some colour utils. Refactor the FontDialog. Improving the ColourPanel and ColourDialog. Created a Settings loader. --- .../backend/utils/URSettingsLoader.java | 43 +++++++++++ src/urChatBasic/base/Constants.java | 8 ++- src/urChatBasic/base/IRCRoomBase.java | 4 +- src/urChatBasic/frontend/LineFormatter.java | 13 +++- src/urChatBasic/frontend/UserGUI.java | 6 +- .../frontend/components/ColourPanel.java | 72 +++++++++---------- .../frontend/components/FontPanel.java | 19 ++--- .../frontend/dialogs/ColourDialog.java | 24 ++++--- .../frontend/dialogs/FontDialog.java | 7 +- src/urChatBasic/frontend/utils/URColour.java | 12 ++++ 10 files changed, 137 insertions(+), 71 deletions(-) create mode 100644 src/urChatBasic/backend/utils/URSettingsLoader.java diff --git a/src/urChatBasic/backend/utils/URSettingsLoader.java b/src/urChatBasic/backend/utils/URSettingsLoader.java new file mode 100644 index 0000000..1da1b45 --- /dev/null +++ b/src/urChatBasic/backend/utils/URSettingsLoader.java @@ -0,0 +1,43 @@ +package urChatBasic.backend.utils; + +import java.awt.Color; +import java.awt.Font; +import java.util.HashMap; +import java.util.Map; +import java.util.prefs.Preferences; +import urChatBasic.base.Constants; +import urChatBasic.frontend.utils.URColour; + +public class URSettingsLoader { + + public static Font loadFont(Font defaultFont, Preferences settingsPath) + { + Font savedFont = defaultFont; + int savedFontBoldItalic = 0; + + if (settingsPath.getBoolean(Constants.KEY_FONT_BOLD, defaultFont.isBold())) + savedFontBoldItalic = Font.BOLD; + if (settingsPath.getBoolean(Constants.KEY_FONT_ITALIC, defaultFont.isItalic())) + savedFontBoldItalic |= Font.ITALIC; + + savedFont = new Font(settingsPath.get(Constants.KEY_FONT_FAMILY, defaultFont.getFamily()), + savedFontBoldItalic, settingsPath.getInt(Constants.KEY_FONT_SIZE, defaultFont.getSize())); + + return savedFont; + } + + public static Map loadFontColours(Color foreground, Color background, Preferences settingsPath) + { + Map colourMap = new HashMap(); + colourMap.put(Constants.KEY_FONT_FOREGROUND, foreground); + colourMap.put(Constants.KEY_FONT_BACKGROUND, background); + + String loadedForeground = settingsPath.get(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(foreground)); + String loadedBackground = settingsPath.get(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(background)); + + colourMap.replace(Constants.KEY_FONT_FOREGROUND, URColour.hexDecode(loadedForeground)); + colourMap.replace(Constants.KEY_FONT_BACKGROUND, URColour.hexDecode(loadedBackground)); + + return colourMap; + } +} diff --git a/src/urChatBasic/base/Constants.java b/src/urChatBasic/base/Constants.java index 2b13008..724491a 100644 --- a/src/urChatBasic/base/Constants.java +++ b/src/urChatBasic/base/Constants.java @@ -14,6 +14,7 @@ import urChatBasic.base.capabilities.CapabilityTypes; import urChatBasic.frontend.DriverGUI; import urChatBasic.frontend.components.URVersionLabel; +import urChatBasic.frontend.utils.URColour; /** * Used to store constants that are the same and do not change often. These are things used commonly @@ -34,7 +35,8 @@ public class Constants private static Handler LOGGER_TO_FILE; public static Logger LOGGER = Logger.getLogger("Main"); public static String LOGFILE_NAME = "Errors.log"; - private static final Font DEFAULT_FONT = new Font(new JLabel().getFont().getFamily(), 0, new JLabel().getFont().getSize()); + private static final JLabel DEFAULT_LABEL = new JLabel(); + private static final Font DEFAULT_FONT = new Font(DEFAULT_LABEL.getFont().getFamily(), 0, DEFAULT_LABEL.getFont().getSize()); // Preferences public static final Preferences BASE_PREFS = Preferences.userNodeForPackage(DriverGUI.class).node("profiles"); @@ -73,6 +75,8 @@ public class Constants public static final String KEY_FONT_BOLD = "font bold"; public static final String KEY_FONT_ITALIC = "font italic"; public static final String KEY_FONT_SIZE = "font size"; + public static final String KEY_FONT_FOREGROUND = "font foreground"; + public static final String KEY_FONT_BACKGROUND = "font background"; public static final String KEY_WINDOW_X = "window position x"; public static final String KEY_WINDOW_Y = "window position y"; public static final String KEY_WINDOW_WIDTH = "window position width"; @@ -108,6 +112,8 @@ public class Constants public static final String DEFAULT_LIMIT_SERVER_LINES_COUNT = "500"; public static final Boolean DEFAULT_LOG_CLIENT_TEXT = true; public static final Font DEFAULT_FONT_GENERAL = DEFAULT_FONT; + public static final String DEFAULT_FONT_FOREGROUND = URColour.hexEncode(DEFAULT_LABEL.getForeground()); + public static final String DEFAULT_FONT_BACKGROUND = URColour.hexEncode(DEFAULT_LABEL.getBackground()); public static final int DEFAULT_EVENT_TICKER_DELAY = 10; public static final int DEFAULT_WINDOW_X = 0; public static final int DEFAULT_WINDOW_Y = 0; diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 60811e2..d40ff75 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -171,13 +171,13 @@ private void initRoom() if (null != getServer()) { roomPrefs = gui.getFavouritesPath().node(getServer().getName()).node(roomName); - fontDialog = new FontDialog(roomName, gui.getFont(), roomPrefs); + fontDialog = new FontDialog(gui.getFont(), roomPrefs, roomName); lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer(), roomPrefs); } else { roomPrefs = gui.getFavouritesPath().node(roomName); - fontDialog = new FontDialog(roomName, gui.getFont(), roomPrefs); + fontDialog = new FontDialog(gui.getFont(), roomPrefs, roomName); lineFormatter = new LineFormatter(getFontPanel().getFont(), null, roomPrefs); } diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 228326b..4a0b584 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -175,10 +175,11 @@ public SimpleAttributeSet urlStyle() SimpleAttributeSet tempStyle = defaultStyle(name); + tempStyle.addAttribute("name", name); tempStyle.addAttribute("type", "url"); StyleConstants.setForeground(tempStyle, UIManager.getColor("CheckBoxMenuItem.selectionBackground")); - + StyleConstants.setBold(tempStyle, true); StyleConstants.setUnderline(tempStyle, true); tempStyle = loadFontStyle(name, tempStyle); @@ -186,15 +187,23 @@ public SimpleAttributeSet urlStyle() return tempStyle; } + // TODO: urlStyle and channelStyle don't load the correct styling in the fontPanel + public SimpleAttributeSet channelStyle() { String name = "channelStyle"; - SimpleAttributeSet tempStyle = urlStyle(); + SimpleAttributeSet tempStyle = defaultStyle(name); tempStyle.addAttribute("name", name); tempStyle.addAttribute("type", "channel"); + StyleConstants.setForeground(tempStyle, UIManager.getColor("CheckBoxMenuItem.selectionBackground")); + StyleConstants.setBold(tempStyle, true); + StyleConstants.setUnderline(tempStyle, true); + + tempStyle = loadFontStyle(name, tempStyle); + return tempStyle; } diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 9f002a3..1d9999b 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -839,7 +839,7 @@ public Component getListCellRendererComponent(JList list, Object value, int i lafOptions.addActionListener(new ChangeLAFListener()); - clientFontPanel = new FontPanel(getFont(), getProfilePath(), "Global Font:"); + clientFontPanel = new FontPanel(getFont(), getProfilePath(), "Global Font"); clientFontPanel.setPreferredSize(new Dimension(700, 64)); clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); clientFontPanel.getResetButton().addActionListener(new ResetFontListener()); @@ -927,7 +927,7 @@ public void mouseClicked(MouseEvent e) if (SwingUtilities.isRightMouseButton(e) && wordAttributeSet.getAttribute("name") != null) { String styleName = styleLabel.getText(); - FontDialog styleFontDialog = new FontDialog(styleName, clientFontPanel.getFont(), getProfilePath().node(styleName)); + FontDialog styleFontDialog = new FontDialog(clientFontPanel.getFont(), getProfilePath().node(styleName), styleName); styleFontDialog.addSaveListener(new ActionListener() { @@ -1146,7 +1146,7 @@ public FavouritesItem(String favServer, String favChannel) this.favChannel = favChannel; settingsPath = getFavouritesPath().node(favServer).node(favChannel); - favFontDialog = new FontDialog("Font: " + favChannel, UserGUI.this.getFont(), settingsPath); + favFontDialog = new FontDialog(UserGUI.this.getFont(), settingsPath, "Font: " + favChannel); favFontDialog.addSaveListener(new SaveChannelFontListener()); createPopUp(); } diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index d712dac..659f8d2 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -1,58 +1,58 @@ package urChatBasic.frontend.components; import java.awt.*; +import java.util.HashMap; +import java.util.Map; +import java.util.prefs.Preferences; import javax.swing.*; import javax.swing.event.*; +import urChatBasic.backend.utils.URSettingsLoader; +import urChatBasic.base.Constants; /* ColorChooserDemo.java requires no other files. */ -public class ColourPanel extends JPanel - implements ChangeListener { - +public class ColourPanel extends JPanel implements ChangeListener { protected JColorChooser tcc; + public Color selectedColor; + private Color defaultForeground; + private Color defaultBackground; + private Font displayFont; + private Preferences settingsPath; - public ColourPanel() { + public ColourPanel(Font displayFont, Preferences settingsPath) { super(new BorderLayout()); + this.settingsPath = settingsPath; + this.displayFont = displayFont; + defaultForeground = getForeground(); + defaultBackground = getBackground(); //Set up color chooser for setting text color - tcc = new JColorChooser(getForeground()); + tcc = new JColorChooser(defaultForeground); + tcc.getPreviewPanel().setFont(this.displayFont); tcc.getSelectionModel().addChangeListener(this); - tcc.setBorder(BorderFactory.createTitledBorder( - "Choose Text Color")); add(tcc, BorderLayout.PAGE_END); } - public void stateChanged(ChangeEvent e) { - Color newColor = tcc.getColor(); - } + public void loadColours() + { + Map colourMap = URSettingsLoader.loadFontColours(defaultForeground, defaultBackground, settingsPath); + + defaultBackground = colourMap.get(Constants.KEY_FONT_BACKGROUND); + defaultForeground = colourMap.get(Constants.KEY_FONT_FOREGROUND); + // int savedFontBoldItalic = 0; - /** - * Create the GUI and show it. For thread safety, - * this method should be invoked from the - * event-dispatching thread. - */ - private static void createAndShowGUI() { - //Create and set up the window. - JFrame frame = new JFrame("ColorChooserDemo"); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - //Create and set up the content pane. - JComponent newContentPane = new ColourPanel(); - newContentPane.setOpaque(true); //content panes must be opaque - frame.setContentPane(newContentPane); - - //Display the window. - frame.pack(); - frame.setVisible(true); + // if (settingsPath.getBoolean(Constants.KEY_FONT_BOLD, defaultFont.isBold())) + // savedFontBoldItalic = Font.BOLD; + // if (settingsPath.getBoolean(Constants.KEY_FONT_ITALIC, defaultFont.isItalic())) + // savedFontBoldItalic |= Font.ITALIC; + + // savedFont = new Font(settingsPath.get(Constants.KEY_FONT_FAMILY, defaultFont.getFamily()), + // savedFontBoldItalic, settingsPath.getInt(Constants.KEY_FONT_SIZE, defaultFont.getSize())); + + // setFont(savedFont, false); } - public static void main(String[] args) { - //Schedule a job for the event-dispatching thread: - //creating and showing this application's GUI. - javax.swing.SwingUtilities.invokeLater(new Runnable() { - public void run() { - createAndShowGUI(); - } - }); + public void stateChanged(ChangeEvent e) { + selectedColor = tcc.getColor(); } } diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index c3957a7..c665a16 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -17,7 +17,9 @@ import java.util.prefs.Preferences; import javax.swing.*; import urChatBasic.base.Constants; +import urChatBasic.frontend.LineFormatter; import urChatBasic.frontend.dialogs.ColourDialog; +import urChatBasic.backend.utils.URSettingsLoader; public class FontPanel extends JPanel { @@ -46,7 +48,7 @@ public class FontPanel extends JPanel private Preferences settingsPath; - public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) + public FontPanel(Font defaultFont, Preferences settingsPath, String displayName) { setLayout(new GridBagLayout()); setSettingsPath(settingsPath); @@ -60,7 +62,7 @@ public FontPanel(Font defaultFont, Preferences settingsPath, String fontName) public void actionPerformed(ActionEvent arg0) { if(colourDialog == null) - colourDialog = new ColourDialog(fontName, settingsPath); + colourDialog = new ColourDialog(displayName, defaultFont, settingsPath); colourDialog.setVisible(true); } @@ -165,18 +167,7 @@ public void resetFont() { public void loadFont() { - Font savedFont = defaultFont; - int savedFontBoldItalic = 0; - - if (settingsPath.getBoolean(Constants.KEY_FONT_BOLD, defaultFont.isBold())) - savedFontBoldItalic = Font.BOLD; - if (settingsPath.getBoolean(Constants.KEY_FONT_ITALIC, defaultFont.isItalic())) - savedFontBoldItalic |= Font.ITALIC; - - savedFont = new Font(settingsPath.get(Constants.KEY_FONT_FAMILY, defaultFont.getFamily()), - savedFontBoldItalic, settingsPath.getInt(Constants.KEY_FONT_SIZE, defaultFont.getSize())); - - setFont(savedFont, false); + setFont(URSettingsLoader.loadFont(defaultFont, settingsPath), false); } @Override diff --git a/src/urChatBasic/frontend/dialogs/ColourDialog.java b/src/urChatBasic/frontend/dialogs/ColourDialog.java index aedbe3e..714b92f 100644 --- a/src/urChatBasic/frontend/dialogs/ColourDialog.java +++ b/src/urChatBasic/frontend/dialogs/ColourDialog.java @@ -1,6 +1,7 @@ package urChatBasic.frontend.dialogs; -import java.awt.Dimension; +import java.awt.Color; +import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.prefs.Preferences; @@ -12,15 +13,15 @@ public class ColourDialog extends DialogBase { private ColourPanel colourPanel; - public ColourDialog(String title, Preferences settingsPath) + public ColourDialog(String title, Font defaultFont, Preferences settingsPath) { super(DriverGUI.frame, title, true); - initColourDialog(settingsPath); + initColourDialog(defaultFont, settingsPath); } - public void initColourDialog(Preferences settingsPath) + public void initColourDialog(Font defaultFont, Preferences settingsPath) { - colourPanel = new ColourPanel(); + colourPanel = new ColourPanel(defaultFont, settingsPath); add(colourPanel); setContentPane(colourPanel); @@ -32,12 +33,13 @@ public void initColourDialog(Preferences settingsPath) setLocationRelativeTo(super.getParent()); } - // @Override - // public void setVisible(boolean b) - // { - // fontPanel.loadFont(); - // super.setVisible(b); - // } + @Override + public void setVisible(boolean b) + { + setLocationRelativeTo(super.getParent()); + + super.setVisible(b); + } // public void addSaveListener(ActionListener newActionListener) // { diff --git a/src/urChatBasic/frontend/dialogs/FontDialog.java b/src/urChatBasic/frontend/dialogs/FontDialog.java index a1ec6bf..5ab3f55 100644 --- a/src/urChatBasic/frontend/dialogs/FontDialog.java +++ b/src/urChatBasic/frontend/dialogs/FontDialog.java @@ -11,11 +11,13 @@ public class FontDialog extends DialogBase { + private String title = "Default Font"; private FontPanel fontPanel; - public FontDialog(String title, Font defaultFont, Preferences settingsPath) + public FontDialog(Font defaultFont, Preferences settingsPath, String title) { super(DriverGUI.frame, title, true); + this.title = title; initFontDialog(defaultFont, settingsPath); } @@ -26,7 +28,7 @@ public void initFontDialog(Font defaultFont, Preferences settingsPath) setMaximumSize(new Dimension(600, 100)); setLocationRelativeTo(super.getParent()); - fontPanel = new FontPanel(defaultFont, settingsPath, "Default Font:"); + fontPanel = new FontPanel(defaultFont, settingsPath, title); add(fontPanel); } @@ -39,6 +41,7 @@ public FontPanel getFontPanel() @Override public void setVisible(boolean b) { + setLocationRelativeTo(super.getParent()); fontPanel.loadFont(); super.setVisible(b); } diff --git a/src/urChatBasic/frontend/utils/URColour.java b/src/urChatBasic/frontend/utils/URColour.java index 4765cab..45c59de 100644 --- a/src/urChatBasic/frontend/utils/URColour.java +++ b/src/urChatBasic/frontend/utils/URColour.java @@ -38,4 +38,16 @@ public static Color getInvertedColour(Color sourceColour) { // Create and return a new Color object return new Color(r, g, b); } + + public static String hexEncode (Color sourceColor) + { + String hex = Integer.toHexString(sourceColor.getRGB()); + return hex = "#" + hex.substring(2, hex.length()); + } + + public static Color hexDecode (String hexString) + { + Color colour = Color.decode(hexString); + return colour; + } } From 0f3146593ade08ba9f1e533a98d7a0c3538b85ad Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 30 Nov 2023 06:39:33 +1000 Subject: [PATCH 57/78] Some refactoring to use Lambdas when creating action listeners. Adding a listener List for the colour panel. Expanded ColourPanel with buttons and listeners. --- .../backend/utils/URSettingsLoader.java | 10 +- src/urChatBasic/frontend/UserGUI.java | 26 ++-- .../frontend/components/ColourPanel.java | 140 ++++++++++++++++-- .../frontend/components/FontPanel.java | 8 +- .../frontend/dialogs/ColourDialog.java | 11 +- 5 files changed, 159 insertions(+), 36 deletions(-) diff --git a/src/urChatBasic/backend/utils/URSettingsLoader.java b/src/urChatBasic/backend/utils/URSettingsLoader.java index 1da1b45..7912336 100644 --- a/src/urChatBasic/backend/utils/URSettingsLoader.java +++ b/src/urChatBasic/backend/utils/URSettingsLoader.java @@ -26,14 +26,14 @@ public static Font loadFont(Font defaultFont, Preferences settingsPath) return savedFont; } - public static Map loadFontColours(Color foreground, Color background, Preferences settingsPath) + public static Map loadFontColours(Color defaultForeground, Color defaultBackground, Preferences settingsPath) { Map colourMap = new HashMap(); - colourMap.put(Constants.KEY_FONT_FOREGROUND, foreground); - colourMap.put(Constants.KEY_FONT_BACKGROUND, background); + colourMap.put(Constants.KEY_FONT_FOREGROUND, defaultForeground); + colourMap.put(Constants.KEY_FONT_BACKGROUND, defaultBackground); - String loadedForeground = settingsPath.get(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(foreground)); - String loadedBackground = settingsPath.get(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(background)); + String loadedForeground = settingsPath.get(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(defaultForeground)); + String loadedBackground = settingsPath.get(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(defaultBackground)); colourMap.replace(Constants.KEY_FONT_FOREGROUND, URColour.hexDecode(loadedForeground)); colourMap.replace(Constants.KEY_FONT_BACKGROUND, URColour.hexDecode(loadedBackground)); diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 1d9999b..d55fd44 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -917,31 +917,23 @@ public void updatePreviewTextArea() class PreviewClickListener extends MouseInputAdapter { - public void mouseClicked(MouseEvent e) + public void mouseClicked(MouseEvent mouseEvent) { StyledDocument doc = previewTextArea.getStyledDocument(); - Element wordElement = doc.getCharacterElement(previewTextArea.viewToModel2D((e.getPoint()))); + Element wordElement = doc.getCharacterElement(previewTextArea.viewToModel2D((mouseEvent.getPoint()))); AttributeSet wordAttributeSet = wordElement.getAttributes(); ClickableText isClickableText = (ClickableText) wordAttributeSet.getAttribute("clickableText"); - if (SwingUtilities.isRightMouseButton(e) && wordAttributeSet.getAttribute("name") != null) + if (SwingUtilities.isRightMouseButton(mouseEvent) && wordAttributeSet.getAttribute("name") != null) { String styleName = styleLabel.getText(); FontDialog styleFontDialog = new FontDialog(clientFontPanel.getFont(), getProfilePath().node(styleName), styleName); - styleFontDialog.addSaveListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - - List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); - - - // TODO: Need to save attributes and updateStyles after.. - // Currently runs the save after updateStyles - previewLineFormatter.updateStyles(doc, 0); - } - + styleFontDialog.addSaveListener(arg0 -> { + List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); + // TODO: Need to save attributes and updateStyles after.. + // Currently runs the save after updateStyles + previewLineFormatter.updateStyles(doc, 0); }); // styleFontDialog.addResetListener(new ActionListener() { @@ -962,7 +954,7 @@ public void actionPerformed(ActionEvent arg0) { styleFontDialog.setVisible(true); - } else if (SwingUtilities.isLeftMouseButton(e) && null != isClickableText) + } else if (SwingUtilities.isLeftMouseButton(mouseEvent) && null != isClickableText) { isClickableText.execute(); } diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index 659f8d2..6585455 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -1,6 +1,8 @@ package urChatBasic.frontend.components; import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; @@ -8,51 +10,165 @@ import javax.swing.event.*; import urChatBasic.backend.utils.URSettingsLoader; import urChatBasic.base.Constants; +import urChatBasic.frontend.utils.URColour; /* ColorChooserDemo.java requires no other files. */ -public class ColourPanel extends JPanel implements ChangeListener { +public class ColourPanel extends JPanel implements ChangeListener +{ + protected EventListenerList listenerList = new EventListenerList(); + protected transient ActionEvent actionEvent = null; + protected JColorChooser tcc; public Color selectedColor; private Color defaultForeground; private Color defaultBackground; private Font displayFont; private Preferences settingsPath; + private JPanel bottomPanel; + private boolean isForeground = true; + JButton saveButton; + JLabel previewLabel; - public ColourPanel(Font displayFont, Preferences settingsPath) { + public ColourPanel(Font displayFont, Preferences settingsPath) + { super(new BorderLayout()); this.settingsPath = settingsPath; this.displayFont = displayFont; - defaultForeground = getForeground(); - defaultBackground = getBackground(); + Map loadedColours = URSettingsLoader.loadFontColours(getForeground(), getBackground(), settingsPath); + defaultForeground = loadedColours.get(Constants.KEY_FONT_FOREGROUND); + defaultBackground = loadedColours.get(Constants.KEY_FONT_BACKGROUND); - //Set up color chooser for setting text color + bottomPanel = createBottomPanel(); + // Set up color chooser for setting text color tcc = new JColorChooser(defaultForeground); - tcc.getPreviewPanel().setFont(this.displayFont); + tcc.setPreviewPanel(bottomPanel); tcc.getSelectionModel().addChangeListener(this); - + // bottomPanel.setPreferredSize(new Dimension(tcc.getPreferredSize().width, 56)); add(tcc, BorderLayout.PAGE_END); } + public JPanel createBottomPanel() + { + JPanel bottomPanel = new JPanel(); + JButton foregroundButton = new JButton("Toggle Background"); + JButton autoColour = new JButton("Suggest colour"); + JButton resetButton = new JButton("Reset colour"); + saveButton = new JButton("Apply & Save"); + previewLabel = new JLabel("Preview Text"); + previewLabel.setFont(displayFont); + + bottomPanel.setLayout(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + + gbc.gridx = 0; + gbc.gridy = 0; + gbc.gridwidth = 4; + gbc.anchor = GridBagConstraints.CENTER; + bottomPanel.add(previewLabel, gbc); + + gbc.gridx = 0; + gbc.gridy = 1; + gbc.gridwidth = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + bottomPanel.add(foregroundButton, gbc); + + gbc.gridx = 1; + gbc.gridy = 1; + bottomPanel.add(autoColour, gbc); + + gbc.gridx = 2; + gbc.gridy = 1; + bottomPanel.add(resetButton, gbc); + + gbc.gridx = 3; + gbc.gridy = 1; + bottomPanel.add(saveButton, gbc); + + foregroundButton.addActionListener(e -> { + isForeground = !isForeground; + foregroundButton.setText(isForeground ? "Toggle Background" : "Toggle Foreground"); + }); + + resetButton.addActionListener(e -> { + if (isForeground) + { + previewLabel.setForeground(defaultForeground); + } else + { + previewLabel.setOpaque(true); + previewLabel.setBackground(defaultBackground); + } + }); + + autoColour.addActionListener(e -> { + if (isForeground) + { + tcc.setColor(URColour.getInvertedColour(previewLabel.getBackground())); + } else + { + tcc.setColor(URColour.getInvertedColour(previewLabel.getForeground())); + } + }); + + saveButton.addActionListener(e -> { + fireSaveListeners(); + }); + + return bottomPanel; + } + + public void addSaveListener (ActionListener actionListener) + { + // saveButton.addActionListener(actionListener); + listenerList.add(ActionListener.class, actionListener); + } + + protected void fireSaveListeners() + { + Object[] listeners = this.listenerList.getListenerList(); + + for(int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ActionListener.class) { + if (this.actionEvent == null) { + this.actionEvent = new ActionEvent(saveButton, i, TOOL_TIP_TEXT_KEY); + } + + ((ActionListener)listeners[i + 1]).actionPerformed(this.actionEvent); + } + } + } + public void loadColours() { - Map colourMap = URSettingsLoader.loadFontColours(defaultForeground, defaultBackground, settingsPath); + Map colourMap = + URSettingsLoader.loadFontColours(defaultForeground, defaultBackground, settingsPath); defaultBackground = colourMap.get(Constants.KEY_FONT_BACKGROUND); defaultForeground = colourMap.get(Constants.KEY_FONT_FOREGROUND); // int savedFontBoldItalic = 0; // if (settingsPath.getBoolean(Constants.KEY_FONT_BOLD, defaultFont.isBold())) - // savedFontBoldItalic = Font.BOLD; + // savedFontBoldItalic = Font.BOLD; // if (settingsPath.getBoolean(Constants.KEY_FONT_ITALIC, defaultFont.isItalic())) - // savedFontBoldItalic |= Font.ITALIC; + // savedFontBoldItalic |= Font.ITALIC; // savedFont = new Font(settingsPath.get(Constants.KEY_FONT_FAMILY, defaultFont.getFamily()), - // savedFontBoldItalic, settingsPath.getInt(Constants.KEY_FONT_SIZE, defaultFont.getSize())); + // savedFontBoldItalic, settingsPath.getInt(Constants.KEY_FONT_SIZE, defaultFont.getSize())); // setFont(savedFont, false); } - public void stateChanged(ChangeEvent e) { + public void stateChanged(ChangeEvent e) + { selectedColor = tcc.getColor(); + + if (isForeground) + { + previewLabel.setForeground(selectedColor); + } else + { + previewLabel.setOpaque(true); + previewLabel.setBackground(selectedColor); + } } } diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index c665a16..3af8ae7 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -62,7 +62,13 @@ public FontPanel(Font defaultFont, Preferences settingsPath, String displayName) public void actionPerformed(ActionEvent arg0) { if(colourDialog == null) - colourDialog = new ColourDialog(displayName, defaultFont, settingsPath); + { + colourDialog = new ColourDialog(displayName, FontPanel.this.getFont(), settingsPath); + + colourDialog.getColourPanel().addSaveListener(e -> { + System.out.println("Save pressed"); + }); + } colourDialog.setVisible(true); } diff --git a/src/urChatBasic/frontend/dialogs/ColourDialog.java b/src/urChatBasic/frontend/dialogs/ColourDialog.java index 714b92f..4e2e3a7 100644 --- a/src/urChatBasic/frontend/dialogs/ColourDialog.java +++ b/src/urChatBasic/frontend/dialogs/ColourDialog.java @@ -1,6 +1,5 @@ package urChatBasic.frontend.dialogs; -import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -31,6 +30,16 @@ public void initColourDialog(Font defaultFont, Preferences settingsPath) setResizable(false); // setMaximumSize(new Dimension(600, 600)); setLocationRelativeTo(super.getParent()); + + colourPanel.addSaveListener(e -> { + ColourDialog.this.setVisible(false); + System.out.println("Set visible false"); + }); + } + + public ColourPanel getColourPanel() + { + return colourPanel; } @Override From 47f73a998117eb7a147eca188945d70444edf3fd Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 1 Dec 2023 18:19:18 +1000 Subject: [PATCH 58/78] working ont it --- ...ingsLoader.java => URPreferencesUtil.java} | 8 +- src/urChatBasic/base/IRCRoomBase.java | 6 +- src/urChatBasic/frontend/LineFormatter.java | 56 +++++++++----- src/urChatBasic/frontend/UserGUI.java | 7 +- .../frontend/components/ColourPanel.java | 74 ++++++++++--------- .../frontend/components/FontPanel.java | 4 +- .../frontend/components/URVersionLabel.java | 16 ++++ 7 files changed, 111 insertions(+), 60 deletions(-) rename src/urChatBasic/backend/utils/{URSettingsLoader.java => URPreferencesUtil.java} (83%) diff --git a/src/urChatBasic/backend/utils/URSettingsLoader.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java similarity index 83% rename from src/urChatBasic/backend/utils/URSettingsLoader.java rename to src/urChatBasic/backend/utils/URPreferencesUtil.java index 7912336..75ed8fb 100644 --- a/src/urChatBasic/backend/utils/URSettingsLoader.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -8,7 +8,7 @@ import urChatBasic.base.Constants; import urChatBasic.frontend.utils.URColour; -public class URSettingsLoader { +public class URPreferencesUtil { public static Font loadFont(Font defaultFont, Preferences settingsPath) { @@ -40,4 +40,10 @@ public static Map loadFontColours(Color defaultForeground, Color return colourMap; } + + public static void saveFontColours(Color newForeground, Color newBackground, Preferences settingsPath) + { + settingsPath.put(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(newForeground)); + settingsPath.put(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(newBackground)); + } } diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index d40ff75..ba9e889 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -173,13 +173,13 @@ private void initRoom() roomPrefs = gui.getFavouritesPath().node(getServer().getName()).node(roomName); fontDialog = new FontDialog(gui.getFont(), roomPrefs, roomName); - lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer(), roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getFont(), gui.getDefaultColours() , getServer(), roomPrefs); } else { roomPrefs = gui.getFavouritesPath().node(roomName); fontDialog = new FontDialog(gui.getFont(), roomPrefs, roomName); - lineFormatter = new LineFormatter(getFontPanel().getFont(), null, roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getFont(), gui.getDefaultColours() , null, roomPrefs); } setFont(getFontPanel().getFont()); @@ -240,7 +240,7 @@ public FontPanel getFontPanel() public void resetLineFormatter() { - lineFormatter = new LineFormatter(getFontPanel().getFont(), getServer(), roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getFont(), gui.getDefaultColours() , getServer(), roomPrefs); } private void setupMainTextArea() diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 4a0b584..73c06e4 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -25,6 +25,7 @@ import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; +import urChatBasic.backend.utils.URPreferencesUtil; import urChatBasic.base.Constants; import urChatBasic.base.IRCServerBase; import urChatBasic.frontend.dialogs.YesNoDialog; @@ -34,15 +35,16 @@ public class LineFormatter { private String myNick; private Font myFont; + private Color myForeground; + private Color myBackground; private IRCServerBase myServer; private Preferences formatterPrefs; public SimpleAttributeSet timeStyle; public SimpleAttributeSet lineStyle; public SimpleAttributeSet nickStyle; public SimpleAttributeSet myStyle; - protected UserGUI gui = DriverGUI.gui; - public LineFormatter(Font myFont, final IRCServerBase server, Preferences formatterPrefs) + public LineFormatter(Font myFont, Map defaultColours, final IRCServerBase server, Preferences formatterPrefs) { // TODO: Need to load attributes from formatterPrefs this.formatterPrefs = formatterPrefs; @@ -58,6 +60,11 @@ public LineFormatter(Font myFont, final IRCServerBase server, Preferences format } this.myFont = myFont; + // TODO: should we be using something like UIManager + // UIManager.getFont for the default fonts isntead? + myForeground = UIManager.getColor("Label.foreground"); + myBackground = UIManager.getColor("Label.background"); + timeStyle = defaultStyle(null); lineStyle = defaultStyle(null); nickStyle = nickStyle(); @@ -73,18 +80,24 @@ public void setFont(StyledDocument doc, Font newFont) public SimpleAttributeSet loadFontStyle(String name, SimpleAttributeSet loadedStyle) { + Font loadedFont = URPreferencesUtil.loadFont(myFont, formatterPrefs.node(name)); + Map loadedColours = URPreferencesUtil.loadFontColours(myForeground, myBackground, formatterPrefs.node(name)); StyleConstants.setFontFamily(loadedStyle, - formatterPrefs.node(name).get("font family", StyleConstants.getFontFamily(loadedStyle).toString())); + loadedFont.getFamily()); StyleConstants.setFontSize(loadedStyle, - formatterPrefs.node(name).getInt("font size", StyleConstants.getFontSize(loadedStyle))); + loadedFont.getSize()); StyleConstants.setBold(loadedStyle, - formatterPrefs.node(name).getBoolean("font bold", StyleConstants.isBold(loadedStyle))); + loadedFont.isBold()); StyleConstants.setItalic(loadedStyle, - formatterPrefs.node(name).getBoolean("font italic", StyleConstants.isItalic(loadedStyle))); + loadedFont.isItalic()); + + StyleConstants.setForeground(loadedStyle, loadedColours.get(Constants.KEY_FONT_FOREGROUND)); + + StyleConstants.setBackground(loadedStyle, loadedColours.get(Constants.KEY_FONT_BACKGROUND)); // TODO: Allow for underline and strikethrough // StyleConstants.setUnderline(defaultStyle, @@ -105,14 +118,17 @@ public SimpleAttributeSet defaultStyle(String name) defaultStyle.addAttribute("name", name); defaultStyle.addAttribute("type", "default"); // get the contrasting colour of the background colour - StyleConstants.setForeground(defaultStyle, new Color(formatterPrefs.node(name).getInt("font foreground", - URColour.getContrastColour(UIManager.getColor("Panel.background")).getRGB()))); + // StyleConstants.setForeground(defaultStyle, new Color(formatterPrefs.node(name).getInt("font foreground", + // URColour.getContrastColour(UIManager.getColor("Panel.background")).getRGB()))); StyleConstants.setFontFamily(defaultStyle, myFont.getFamily()); StyleConstants.setFontSize(defaultStyle, myFont.getSize()); StyleConstants.setBold(defaultStyle, myFont.isBold()); StyleConstants.setItalic(defaultStyle, myFont.isItalic()); + StyleConstants.setForeground(defaultStyle, myForeground); + StyleConstants.setBackground(defaultStyle, myBackground); + defaultStyle = loadFontStyle(name, defaultStyle); return defaultStyle; @@ -124,16 +140,20 @@ public SimpleAttributeSet lowStyle() SimpleAttributeSet tempStyle = defaultStyle(name); - if (URColour.useDarkColour(UIManager.getColor("Panel.background"))) - { - StyleConstants.setForeground(tempStyle, Color.DARK_GRAY); - } else - { - StyleConstants.setForeground(tempStyle, Color.LIGHT_GRAY); - } + + StyleConstants.setForeground(tempStyle, UIManager.getColor("Panel.background").darker()); tempStyle = loadFontStyle(name, tempStyle); + if(StyleConstants.getForeground(tempStyle).getRGB() == myForeground.getRGB()) + if (URColour.useDarkColour(UIManager.getColor("Panel.background"))) + { + StyleConstants.setForeground(tempStyle, UIManager.getColor("Panel.background").darker()); + } else + { + StyleConstants.setForeground(tempStyle, UIManager.getColor("Panel.background").brighter()); + } + return tempStyle; } @@ -406,7 +426,7 @@ public void updateStyles(StyledDocument doc, int startPosition) SimpleAttributeSet matchingStyle = getStyle(styleName); boolean isDateStyle = false; - if (null != gui && null != textStyle.getAttribute("date")) + if (null != DriverGUI.gui && null != textStyle.getAttribute("date")) { isDateStyle = true; try @@ -422,7 +442,7 @@ public void updateStyles(StyledDocument doc, int startPosition) doc.remove(styleStart, styleLength); } - if (gui.isTimeStampsEnabled()) + if (DriverGUI.gui.isTimeStampsEnabled()) { textStyle.removeAttribute("date"); textStyle.removeAttribute("time"); @@ -656,7 +676,7 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse // doc.insertString(doc.getLength(), timeLine, timeStyle); // if(null != timeLine && !timeLine.isBlank()) - if (!timeLine.isBlank() && gui.isTimeStampsEnabled()) + if (!timeLine.isBlank() && DriverGUI.gui.isTimeStampsEnabled()) { // add the date to the end of the string to preserve the timestamp of the line // when updating styles diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index d55fd44..89b14c6 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -513,6 +513,11 @@ private void setupLeftOptionsPanel() optionsLeftPanel.add(extrasPanel, BorderLayout.SOUTH); } + public Map getDefaultColours() + { + return urVersionLabel.getColours(); + } + private void setupRightOptionsPanel() { ListSelectionModel listSelectionModel = optionsList.getSelectionModel(); @@ -895,7 +900,7 @@ public void updatePreviewTextArea() // } // previewTextArea.setFont(clientFontPanel.getFont()); - previewLineFormatter = new LineFormatter(clientFontPanel.getFont(), null, getProfilePath()); + previewLineFormatter = new LineFormatter(clientFontPanel.getFont(), urVersionLabel.getColours() ,null, getProfilePath()); if(previewDoc.getLength() <= 0) { diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index 6585455..51cf220 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -8,7 +8,7 @@ import java.util.prefs.Preferences; import javax.swing.*; import javax.swing.event.*; -import urChatBasic.backend.utils.URSettingsLoader; +import urChatBasic.backend.utils.URPreferencesUtil; import urChatBasic.base.Constants; import urChatBasic.frontend.utils.URColour; @@ -34,9 +34,13 @@ public ColourPanel(Font displayFont, Preferences settingsPath) super(new BorderLayout()); this.settingsPath = settingsPath; this.displayFont = displayFont; - Map loadedColours = URSettingsLoader.loadFontColours(getForeground(), getBackground(), settingsPath); - defaultForeground = loadedColours.get(Constants.KEY_FONT_FOREGROUND); - defaultBackground = loadedColours.get(Constants.KEY_FONT_BACKGROUND); + saveButton = new JButton("Apply & Save"); + previewLabel = new JLabel("Preview Text"); + previewLabel.setFont(this.displayFont); + + defaultForeground = previewLabel.getForeground(); + defaultBackground = previewLabel.getBackground(); + loadColours(); bottomPanel = createBottomPanel(); // Set up color chooser for setting text color @@ -53,9 +57,7 @@ public JPanel createBottomPanel() JButton foregroundButton = new JButton("Toggle Background"); JButton autoColour = new JButton("Suggest colour"); JButton resetButton = new JButton("Reset colour"); - saveButton = new JButton("Apply & Save"); - previewLabel = new JLabel("Preview Text"); - previewLabel.setFont(displayFont); + bottomPanel.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); @@ -91,13 +93,9 @@ public JPanel createBottomPanel() resetButton.addActionListener(e -> { if (isForeground) - { - previewLabel.setForeground(defaultForeground); - } else - { - previewLabel.setOpaque(true); - previewLabel.setBackground(defaultBackground); - } + setPreviewColour(defaultForeground); + else + setPreviewColour(defaultBackground); }); autoColour.addActionListener(e -> { @@ -114,9 +112,29 @@ public JPanel createBottomPanel() fireSaveListeners(); }); + addSaveListener(e -> { + URPreferencesUtil.saveFontColours(previewLabel.getForeground(), previewLabel.getBackground(), settingsPath); + }); + return bottomPanel; } + private void setPreviewColour (Color newColour) + { + if(isForeground) + { + previewLabel.setForeground(newColour); + } else + { + if(newColour != defaultBackground) + previewLabel.setOpaque(true); + else + previewLabel.setOpaque(false); + + previewLabel.setBackground(newColour); + } + } + public void addSaveListener (ActionListener actionListener) { // saveButton.addActionListener(actionListener); @@ -141,34 +159,20 @@ protected void fireSaveListeners() public void loadColours() { Map colourMap = - URSettingsLoader.loadFontColours(defaultForeground, defaultBackground, settingsPath); - - defaultBackground = colourMap.get(Constants.KEY_FONT_BACKGROUND); - defaultForeground = colourMap.get(Constants.KEY_FONT_FOREGROUND); - // int savedFontBoldItalic = 0; + URPreferencesUtil.loadFontColours(defaultForeground, defaultBackground, settingsPath); - // if (settingsPath.getBoolean(Constants.KEY_FONT_BOLD, defaultFont.isBold())) - // savedFontBoldItalic = Font.BOLD; - // if (settingsPath.getBoolean(Constants.KEY_FONT_ITALIC, defaultFont.isItalic())) - // savedFontBoldItalic |= Font.ITALIC; + // defaultBackground = colourMap.get(Constants.KEY_FONT_BACKGROUND); + // defaultForeground = colourMap.get(Constants.KEY_FONT_FOREGROUND); + previewLabel.setForeground(colourMap.get(Constants.KEY_FONT_FOREGROUND)); - // savedFont = new Font(settingsPath.get(Constants.KEY_FONT_FAMILY, defaultFont.getFamily()), - // savedFontBoldItalic, settingsPath.getInt(Constants.KEY_FONT_SIZE, defaultFont.getSize())); - - // setFont(savedFont, false); + previewLabel.setOpaque(true); + previewLabel.setBackground(colourMap.get(Constants.KEY_FONT_BACKGROUND)); } public void stateChanged(ChangeEvent e) { selectedColor = tcc.getColor(); - if (isForeground) - { - previewLabel.setForeground(selectedColor); - } else - { - previewLabel.setOpaque(true); - previewLabel.setBackground(selectedColor); - } + setPreviewColour(selectedColor); } } diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 3af8ae7..b375b9a 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -19,7 +19,7 @@ import urChatBasic.base.Constants; import urChatBasic.frontend.LineFormatter; import urChatBasic.frontend.dialogs.ColourDialog; -import urChatBasic.backend.utils.URSettingsLoader; +import urChatBasic.backend.utils.URPreferencesUtil; public class FontPanel extends JPanel { @@ -173,7 +173,7 @@ public void resetFont() { public void loadFont() { - setFont(URSettingsLoader.loadFont(defaultFont, settingsPath), false); + setFont(URPreferencesUtil.loadFont(defaultFont, settingsPath), false); } @Override diff --git a/src/urChatBasic/frontend/components/URVersionLabel.java b/src/urChatBasic/frontend/components/URVersionLabel.java index cf4453b..6dfb82d 100644 --- a/src/urChatBasic/frontend/components/URVersionLabel.java +++ b/src/urChatBasic/frontend/components/URVersionLabel.java @@ -4,16 +4,22 @@ import javax.swing.JPanel; import urChatBasic.base.Constants; import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; import java.util.logging.Level; public class URVersionLabel extends JPanel { + // We are using this label as the default foreground and background colours! + private JLabel versionLabel = new JLabel(Constants.UR_VERSION); public URVersionLabel(JPanel parentPanel) @@ -41,6 +47,16 @@ public static void setVersion() { } } + public Map getColours() + { + Map colours = new HashMap<>(); + + colours.put(Constants.KEY_FONT_FOREGROUND, getForeground()); + colours.put(Constants.KEY_FONT_BACKGROUND, getBackground()); + + return colours; + } + private static String findGitFolder() { // Implement logic to find the .git folder in the project directory or its parents // For simplicity, let's assume it's in the current directory From d6037fbf995137da1bbd2b55e25a2b685cbc576a Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 2 Dec 2023 10:37:10 +1000 Subject: [PATCH 59/78] Created a style for handling the font and colours --- .../backend/utils/URPreferencesUtil.java | 29 +++++++ src/urChatBasic/backend/utils/URStyle.java | 75 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 src/urChatBasic/backend/utils/URStyle.java diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index 75ed8fb..6c67aef 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; +import javax.swing.text.StyleConstants; import urChatBasic.base.Constants; import urChatBasic.frontend.utils.URColour; @@ -41,6 +42,34 @@ public static Map loadFontColours(Color defaultForeground, Color return colourMap; } + public static URStyle loadStyle(URStyle defaultStyle, Preferences settingsPath) + { + Preferences stylePrefPath = settingsPath.node(defaultStyle.getAttribute("name").toString()); + + Font loadedFont = loadFont(defaultStyle.getFont(), stylePrefPath); + // LineFormatter.getStyleAsFont(defaultStyle); + Map loadedColours = loadFontColours(defaultStyle.getForeground(), defaultStyle.getBackground(), stylePrefPath); + // LineFormatter.getStyleColours(defaultStyle); + + StyleConstants.setFontFamily(defaultStyle, + loadedFont.getFamily()); + + StyleConstants.setFontSize(defaultStyle, + loadedFont.getSize()); + + StyleConstants.setBold(defaultStyle, + loadedFont.isBold()); + + StyleConstants.setItalic(defaultStyle, + loadedFont.isItalic()); + + StyleConstants.setForeground(defaultStyle, loadedColours.get(Constants.KEY_FONT_FOREGROUND)); + + StyleConstants.setBackground(defaultStyle, loadedColours.get(Constants.KEY_FONT_BACKGROUND)); + + return defaultStyle; + } + public static void saveFontColours(Color newForeground, Color newBackground, Preferences settingsPath) { settingsPath.put(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(newForeground)); diff --git a/src/urChatBasic/backend/utils/URStyle.java b/src/urChatBasic/backend/utils/URStyle.java new file mode 100644 index 0000000..8220b7f --- /dev/null +++ b/src/urChatBasic/backend/utils/URStyle.java @@ -0,0 +1,75 @@ +package urChatBasic.backend.utils; + +import java.awt.Color; +import java.awt.Font; +import javax.swing.UIManager; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import urChatBasic.base.Constants; + +public class URStyle extends SimpleAttributeSet { + + /** + * Create a URStyle with defaults + */ + public URStyle (String name) + { + this(name, Constants.DEFAULT_FONT_GENERAL); + } + + /** + * Create a URStyle based on defaultFont + * @param defaultFont + */ + public URStyle (String name, Font defaultFont) + { + super(); + this.addAttribute("name", name); + setFont(defaultFont); + setForeground(UIManager.getColor("Label.foreground")); + setBackground(UIManager.getColor("Label.background")); + } + + public Font getFont() + { + int savedFontBoldItalic = 0; + + if (StyleConstants.isBold(this)) + savedFontBoldItalic = Font.BOLD; + if (StyleConstants.isItalic(this)) + savedFontBoldItalic |= Font.ITALIC; + + Font styleFont = new Font(StyleConstants.getFontFamily(this), savedFontBoldItalic, + StyleConstants.getFontSize(this)); + + return styleFont; + } + + public void setFont(Font newFont) + { + StyleConstants.setFontFamily(this, newFont.getFamily()); + StyleConstants.setBold(this, newFont.isBold()); + StyleConstants.setItalic(this, newFont.isItalic()); + StyleConstants.setFontSize(this, newFont.getSize()); + } + + public Color getForeground() + { + return StyleConstants.getForeground(this); + } + + public Color getBackground() + { + return StyleConstants.getBackground(this); + } + + public void setForeground(Color newColour) + { + StyleConstants.setForeground(this, newColour); + } + + public void setBackground(Color newColour) + { + StyleConstants.setBackground(this, newColour); + } +} From 26f3240c3f6c96cc3be0a75a13d1c6997f84ad3a Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 3 Dec 2023 06:22:56 +1000 Subject: [PATCH 60/78] Replacing font handling to use URStyle class instead, this is needed to properly handle the colours etc --- .../backend/utils/URPreferencesUtil.java | 47 ++++-- src/urChatBasic/backend/utils/URStyle.java | 19 +++ src/urChatBasic/frontend/LineFormatter.java | 140 +++++++----------- src/urChatBasic/frontend/UserGUI.java | 4 +- .../frontend/components/ColourPanel.java | 38 ++--- .../frontend/components/FontPanel.java | 38 ++--- .../frontend/dialogs/ColourDialog.java | 12 +- 7 files changed, 144 insertions(+), 154 deletions(-) diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index 6c67aef..efb131d 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -11,7 +11,7 @@ public class URPreferencesUtil { - public static Font loadFont(Font defaultFont, Preferences settingsPath) + public static Font loadStyleFont(Font defaultFont, Preferences settingsPath) { Font savedFont = defaultFont; int savedFontBoldItalic = 0; @@ -27,14 +27,14 @@ public static Font loadFont(Font defaultFont, Preferences settingsPath) return savedFont; } - public static Map loadFontColours(Color defaultForeground, Color defaultBackground, Preferences settingsPath) + public static Map loadStyleColours(URStyle defaultStyle, Preferences settingsPath) { Map colourMap = new HashMap(); - colourMap.put(Constants.KEY_FONT_FOREGROUND, defaultForeground); - colourMap.put(Constants.KEY_FONT_BACKGROUND, defaultBackground); + colourMap.put(Constants.KEY_FONT_FOREGROUND, defaultStyle.getForeground()); + colourMap.put(Constants.KEY_FONT_BACKGROUND, defaultStyle.getBackground()); - String loadedForeground = settingsPath.get(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(defaultForeground)); - String loadedBackground = settingsPath.get(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(defaultBackground)); + String loadedForeground = settingsPath.get(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(defaultStyle.getForeground())); + String loadedBackground = settingsPath.get(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(defaultStyle.getBackground())); colourMap.replace(Constants.KEY_FONT_FOREGROUND, URColour.hexDecode(loadedForeground)); colourMap.replace(Constants.KEY_FONT_BACKGROUND, URColour.hexDecode(loadedBackground)); @@ -42,13 +42,13 @@ public static Map loadFontColours(Color defaultForeground, Color return colourMap; } - public static URStyle loadStyle(URStyle defaultStyle, Preferences settingsPath) + public static URStyle loadStyle(URStyle defaultStyle, Preferences baseSettingsPath) { - Preferences stylePrefPath = settingsPath.node(defaultStyle.getAttribute("name").toString()); - - Font loadedFont = loadFont(defaultStyle.getFont(), stylePrefPath); + Preferences stylePrefPath = baseSettingsPath.node(defaultStyle.getAttribute("name").toString()); + System.out.println("Load Style Path: " + stylePrefPath.toString()); + Font loadedFont = loadStyleFont(defaultStyle.getFont(), stylePrefPath); // LineFormatter.getStyleAsFont(defaultStyle); - Map loadedColours = loadFontColours(defaultStyle.getForeground(), defaultStyle.getBackground(), stylePrefPath); + Map loadedColours = loadStyleColours(defaultStyle, stylePrefPath); // LineFormatter.getStyleColours(defaultStyle); StyleConstants.setFontFamily(defaultStyle, @@ -67,10 +67,33 @@ public static URStyle loadStyle(URStyle defaultStyle, Preferences settingsPath) StyleConstants.setBackground(defaultStyle, loadedColours.get(Constants.KEY_FONT_BACKGROUND)); + System.out.println("Loaded: "+defaultStyle.getAttribute("name") + ". Colours - fg: "+URColour.hexEncode(defaultStyle.getForeground()) + " bg: " + URColour.hexEncode(defaultStyle.getBackground())); + return defaultStyle; } - public static void saveFontColours(Color newForeground, Color newBackground, Preferences settingsPath) + public static void saveStyle(URStyle targetStyle, Preferences baseSettingsPath) + { + Preferences stylePrefPath = baseSettingsPath.node(targetStyle.getAttribute("name").toString()); + System.out.println("Save Style Path: " + stylePrefPath.toString()); + saveStyleFont(targetStyle.getFont(), stylePrefPath); + saveStyleColours(targetStyle.getForeground(), targetStyle.getBackground(), stylePrefPath); + } + + /** + * TODO: This should be deprecated and just use a saveStyle method. + * @param newFont + * @param settingsPath + */ + private static void saveStyleFont(Font newFont, Preferences settingsPath) + { + settingsPath.putBoolean(Constants.KEY_FONT_BOLD, newFont.isBold()); + settingsPath.putBoolean(Constants.KEY_FONT_ITALIC, newFont.isItalic()); + settingsPath.put(Constants.KEY_FONT_FAMILY, newFont.getFamily()); + settingsPath.putInt(Constants.KEY_FONT_SIZE, newFont.getSize()); + } + + private static void saveStyleColours(Color newForeground, Color newBackground, Preferences settingsPath) { settingsPath.put(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(newForeground)); settingsPath.put(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(newBackground)); diff --git a/src/urChatBasic/backend/utils/URStyle.java b/src/urChatBasic/backend/utils/URStyle.java index 8220b7f..166d357 100644 --- a/src/urChatBasic/backend/utils/URStyle.java +++ b/src/urChatBasic/backend/utils/URStyle.java @@ -2,6 +2,7 @@ import java.awt.Color; import java.awt.Font; +import java.util.prefs.Preferences; import javax.swing.UIManager; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; @@ -30,6 +31,11 @@ public URStyle (String name, Font defaultFont) setBackground(UIManager.getColor("Label.background")); } + public String getName() + { + return getAttribute("name").toString(); + } + public Font getFont() { int savedFontBoldItalic = 0; @@ -72,4 +78,17 @@ public void setBackground(Color newColour) { StyleConstants.setBackground(this, newColour); } + + public void load(Preferences prefPath) + { + URStyle loadedStyle = URPreferencesUtil.loadStyle(this, prefPath); + setFont(loadedStyle.getFont()); + setForeground(loadedStyle.getForeground()); + setBackground(loadedStyle.getBackground()); + } + + public void save(Preferences prefPath) + { + URPreferencesUtil.saveStyle(this, prefPath); + } } diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 73c06e4..41d78b9 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -26,6 +26,7 @@ import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import urChatBasic.backend.utils.URPreferencesUtil; +import urChatBasic.backend.utils.URStyle; import urChatBasic.base.Constants; import urChatBasic.base.IRCServerBase; import urChatBasic.frontend.dialogs.YesNoDialog; @@ -34,15 +35,15 @@ public class LineFormatter { private String myNick; - private Font myFont; + private URStyle targetStyle; private Color myForeground; private Color myBackground; private IRCServerBase myServer; private Preferences formatterPrefs; - public SimpleAttributeSet timeStyle; - public SimpleAttributeSet lineStyle; - public SimpleAttributeSet nickStyle; - public SimpleAttributeSet myStyle; + public URStyle timeStyle; + public URStyle lineStyle; + public URStyle nickStyle; + public URStyle myStyle; public LineFormatter(Font myFont, Map defaultColours, final IRCServerBase server, Preferences formatterPrefs) { @@ -59,11 +60,14 @@ public LineFormatter(Font myFont, Map defaultColours, final IRCSe myNick = null; } - this.myFont = myFont; + targetStyle = new URStyle(myNick, myFont); + targetStyle.setBackground(defaultColours.get(Constants.KEY_FONT_FOREGROUND)); + targetStyle.setBackground(defaultColours.get(Constants.KEY_FONT_BACKGROUND)); + // TODO: should we be using something like UIManager // UIManager.getFont for the default fonts isntead? - myForeground = UIManager.getColor("Label.foreground"); - myBackground = UIManager.getColor("Label.background"); + myForeground = targetStyle.getForeground(); + myBackground = targetStyle.getBackground(); timeStyle = defaultStyle(null); lineStyle = defaultStyle(null); @@ -73,77 +77,48 @@ public LineFormatter(Font myFont, Map defaultColours, final IRCSe public void setFont(StyledDocument doc, Font newFont) { - myFont = newFont; + targetStyle.setFont(newFont); if (doc.getLength() > 0) updateStyles(doc, 0); } - public SimpleAttributeSet loadFontStyle(String name, SimpleAttributeSet loadedStyle) - { - Font loadedFont = URPreferencesUtil.loadFont(myFont, formatterPrefs.node(name)); - Map loadedColours = URPreferencesUtil.loadFontColours(myForeground, myBackground, formatterPrefs.node(name)); - - StyleConstants.setFontFamily(loadedStyle, - loadedFont.getFamily()); - - StyleConstants.setFontSize(loadedStyle, - loadedFont.getSize()); - - StyleConstants.setBold(loadedStyle, - loadedFont.isBold()); - - StyleConstants.setItalic(loadedStyle, - loadedFont.isItalic()); - - StyleConstants.setForeground(loadedStyle, loadedColours.get(Constants.KEY_FONT_FOREGROUND)); - - StyleConstants.setBackground(loadedStyle, loadedColours.get(Constants.KEY_FONT_BACKGROUND)); - - // TODO: Allow for underline and strikethrough - // StyleConstants.setUnderline(defaultStyle, - // formatterPrefs.node(name).getBoolean("font underline", StyleConstants.isUnderline(defaults))); - - // StyleConstants.setStrikeThrough(defaultStyle, - // formatterPrefs.node(name).getBoolean("font strikethrough", StyleConstants.isStrikeThrough(defaults))); - - return loadedStyle; - } - - public SimpleAttributeSet defaultStyle(String name) + public URStyle defaultStyle(String name) { if (name == null) name = "defaultStyle"; - SimpleAttributeSet defaultStyle = new SimpleAttributeSet(); - defaultStyle.addAttribute("name", name); + + + URStyle defaultStyle = new URStyle(name, targetStyle.getFont()); defaultStyle.addAttribute("type", "default"); // get the contrasting colour of the background colour // StyleConstants.setForeground(defaultStyle, new Color(formatterPrefs.node(name).getInt("font foreground", // URColour.getContrastColour(UIManager.getColor("Panel.background")).getRGB()))); - StyleConstants.setFontFamily(defaultStyle, myFont.getFamily()); - StyleConstants.setFontSize(defaultStyle, myFont.getSize()); - StyleConstants.setBold(defaultStyle, myFont.isBold()); - StyleConstants.setItalic(defaultStyle, myFont.isItalic()); + StyleConstants.setFontFamily(defaultStyle, targetStyle.getFont().getFamily()); + StyleConstants.setFontSize(defaultStyle, targetStyle.getFont().getSize()); + StyleConstants.setBold(defaultStyle, targetStyle.getFont().isBold()); + StyleConstants.setItalic(defaultStyle, targetStyle.getFont().isItalic()); StyleConstants.setForeground(defaultStyle, myForeground); StyleConstants.setBackground(defaultStyle, myBackground); - defaultStyle = loadFontStyle(name, defaultStyle); + // defaultStyle = loadFontStyle(name, defaultStyle); + defaultStyle = URPreferencesUtil.loadStyle(defaultStyle, formatterPrefs); return defaultStyle; } - public SimpleAttributeSet lowStyle() + public URStyle lowStyle() { String name = "lowStyle"; - SimpleAttributeSet tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name); StyleConstants.setForeground(tempStyle, UIManager.getColor("Panel.background").darker()); - tempStyle = loadFontStyle(name, tempStyle); + tempStyle = URPreferencesUtil.loadStyle(tempStyle, formatterPrefs); if(StyleConstants.getForeground(tempStyle).getRGB() == myForeground.getRGB()) if (URColour.useDarkColour(UIManager.getColor("Panel.background"))) @@ -157,43 +132,40 @@ public SimpleAttributeSet lowStyle() return tempStyle; } - public SimpleAttributeSet mediumStyle() + public URStyle mediumStyle() { String name = "mediumStyle"; - SimpleAttributeSet tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name); - tempStyle = loadFontStyle(name, tempStyle); + tempStyle.load(formatterPrefs); return tempStyle; } - public SimpleAttributeSet highStyle() + public URStyle highStyle() { String name = "highStyle"; - SimpleAttributeSet tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name); - StyleConstants.setBackground(tempStyle, UIManager.getColor("CheckBoxMenuItem.selectionBackground")); // TODO: - // Get - // highlight - // colour? + StyleConstants.setBackground(tempStyle, UIManager.getColor("CheckBoxMenuItem.selectionBackground")); StyleConstants.setForeground(tempStyle, URColour.getContrastColour(UIManager.getColor("CheckBoxMenuItem.selectionBackground"))); StyleConstants.setBold(tempStyle, true); StyleConstants.setItalic(tempStyle, true); - tempStyle = loadFontStyle(name, tempStyle); + tempStyle.load(formatterPrefs); return tempStyle; } - public SimpleAttributeSet urlStyle() + public URStyle urlStyle() { String name = "urlStyle"; - SimpleAttributeSet tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name); tempStyle.addAttribute("name", name); tempStyle.addAttribute("type", "url"); @@ -202,18 +174,18 @@ public SimpleAttributeSet urlStyle() StyleConstants.setBold(tempStyle, true); StyleConstants.setUnderline(tempStyle, true); - tempStyle = loadFontStyle(name, tempStyle); + tempStyle.load(formatterPrefs); return tempStyle; } // TODO: urlStyle and channelStyle don't load the correct styling in the fontPanel - public SimpleAttributeSet channelStyle() + public URStyle channelStyle() { String name = "channelStyle"; - SimpleAttributeSet tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name); tempStyle.addAttribute("name", name); tempStyle.addAttribute("type", "channel"); @@ -222,16 +194,16 @@ public SimpleAttributeSet channelStyle() StyleConstants.setBold(tempStyle, true); StyleConstants.setUnderline(tempStyle, true); - tempStyle = loadFontStyle(name, tempStyle); + tempStyle.load(formatterPrefs); return tempStyle; } - public SimpleAttributeSet myStyle() + public URStyle myStyle() { String name = "myStyle"; - SimpleAttributeSet tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name); tempStyle.addAttribute("type", "myNick"); // StyleConstants.setForeground(tempStyle, Color.GREEN); @@ -241,21 +213,21 @@ public SimpleAttributeSet myStyle() StyleConstants.setBold(tempStyle, true); StyleConstants.setUnderline(tempStyle, true); - tempStyle = loadFontStyle(name, tempStyle); + tempStyle.load(formatterPrefs); return tempStyle; } - public SimpleAttributeSet nickStyle() + public URStyle nickStyle() { String name = "nickStyle"; - SimpleAttributeSet tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name); tempStyle.addAttribute("type", "nick"); StyleConstants.setUnderline(tempStyle, true); - tempStyle = loadFontStyle(name, tempStyle); + tempStyle.load(formatterPrefs); return tempStyle; } @@ -268,10 +240,10 @@ public void setNick(String myNick) public class ClickableText extends AbstractAction { private String textLink; - private SimpleAttributeSet attributeSet; + private URStyle attributeSet; private IRCUser fromUser; - ClickableText(String textLink, SimpleAttributeSet attributeSet, IRCUser fromUser) + ClickableText(String textLink, URStyle attributeSet, IRCUser fromUser) { this.textLink = textLink; this.attributeSet = attributeSet; @@ -375,7 +347,7 @@ private void appendString(StyledDocument doc, String insertedString, SimpleAttri insertString(doc, insertedString, style, position); } - private SimpleAttributeSet getStyle(String styleName) + private URStyle getStyle(String styleName) { switch (styleName) { @@ -571,18 +543,18 @@ public SimpleAttributeSet getStyleAtPosition(StyledDocument doc, int position, S return new SimpleAttributeSet(textStyle); } - private void parseClickableText(StyledDocument doc, IRCUser fromUser, String line, SimpleAttributeSet defaultStyle) + private void parseClickableText(StyledDocument doc, IRCUser fromUser, String line, URStyle defaultStyle) throws BadLocationException { - HashMap regexStrings = new HashMap<>(); + HashMap regexStrings = new HashMap<>(); regexStrings.put(Constants.URL_REGEX, urlStyle()); regexStrings.put(Constants.CHANNEL_REGEX, channelStyle()); // final String line = getLatestLine(doc); final int relativePosition = getLinePosition(doc, getLatestLine(doc)); - ArrayList clickableLines = new ArrayList(); + ArrayList clickableLines = new ArrayList(); - for (Map.Entry entry : regexStrings.entrySet()) + for (Map.Entry entry : regexStrings.entrySet()) { String regex = entry.getKey(); @@ -593,7 +565,7 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin // do stuff for each match while (matcher.find()) { - SimpleAttributeSet linkStyle = getStyle(entry.getValue().getAttribute("name").toString()); + URStyle linkStyle = getStyle(entry.getValue().getAttribute("name").toString()); String clickableLine = matcher.group(1); linkStyle.addAttribute("clickableText", new ClickableText(clickableLine, linkStyle, fromUser)); @@ -613,11 +585,11 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin return Integer.compare(styleStart1, styleStart2); }); - Iterator linesIterator = clickableLines.iterator(); + Iterator linesIterator = clickableLines.iterator(); String remainingLine = line; while (linesIterator.hasNext()) { - SimpleAttributeSet nextLine = linesIterator.next(); + URStyle nextLine = linesIterator.next(); // Offset based on the difference between the original line and the remaining line, // plus the relativePosition within the document. @@ -696,7 +668,7 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse if (fromUser != null) { - SimpleAttributeSet clickableNameStyle = nickStyle; + URStyle clickableNameStyle = nickStyle; clickableNameStyle.addAttribute("type", "IRCUser"); clickableNameStyle.addAttribute("clickableText", new ClickableText(fromUser.toString(), nickStyle, fromUser)); diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 89b14c6..a889bc1 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -844,7 +844,7 @@ public Component getListCellRendererComponent(JList list, Object value, int i lafOptions.addActionListener(new ChangeLAFListener()); - clientFontPanel = new FontPanel(getFont(), getProfilePath(), "Global Font"); + clientFontPanel = new FontPanel(getFont(), getProfilePath(), ""); clientFontPanel.setPreferredSize(new Dimension(700, 64)); clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); clientFontPanel.getResetButton().addActionListener(new ResetFontListener()); @@ -932,7 +932,7 @@ public void mouseClicked(MouseEvent mouseEvent) if (SwingUtilities.isRightMouseButton(mouseEvent) && wordAttributeSet.getAttribute("name") != null) { String styleName = styleLabel.getText(); - FontDialog styleFontDialog = new FontDialog(clientFontPanel.getFont(), getProfilePath().node(styleName), styleName); + FontDialog styleFontDialog = new FontDialog(previewLineFormatter.getStyleAsFont(styleName), getProfilePath(), styleName); styleFontDialog.addSaveListener(arg0 -> { List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index 51cf220..0495002 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -9,6 +9,7 @@ import javax.swing.*; import javax.swing.event.*; import urChatBasic.backend.utils.URPreferencesUtil; +import urChatBasic.backend.utils.URStyle; import urChatBasic.base.Constants; import urChatBasic.frontend.utils.URColour; @@ -20,31 +21,24 @@ public class ColourPanel extends JPanel implements ChangeListener protected JColorChooser tcc; public Color selectedColor; - private Color defaultForeground; - private Color defaultBackground; - private Font displayFont; + private URStyle targetStyle; private Preferences settingsPath; private JPanel bottomPanel; private boolean isForeground = true; JButton saveButton; JLabel previewLabel; - public ColourPanel(Font displayFont, Preferences settingsPath) + public ColourPanel(URStyle targetStyle, Preferences settingsPath) { super(new BorderLayout()); this.settingsPath = settingsPath; - this.displayFont = displayFont; saveButton = new JButton("Apply & Save"); previewLabel = new JLabel("Preview Text"); - previewLabel.setFont(this.displayFont); - - defaultForeground = previewLabel.getForeground(); - defaultBackground = previewLabel.getBackground(); - loadColours(); + previewLabel.setFont(targetStyle.getFont()); bottomPanel = createBottomPanel(); // Set up color chooser for setting text color - tcc = new JColorChooser(defaultForeground); + tcc = new JColorChooser(targetStyle.getForeground()); tcc.setPreviewPanel(bottomPanel); tcc.getSelectionModel().addChangeListener(this); // bottomPanel.setPreferredSize(new Dimension(tcc.getPreferredSize().width, 56)); @@ -93,9 +87,9 @@ public JPanel createBottomPanel() resetButton.addActionListener(e -> { if (isForeground) - setPreviewColour(defaultForeground); + setPreviewColour(targetStyle.getForeground(), isForeground); else - setPreviewColour(defaultBackground); + setPreviewColour(targetStyle.getBackground(), isForeground); }); autoColour.addActionListener(e -> { @@ -113,20 +107,20 @@ public JPanel createBottomPanel() }); addSaveListener(e -> { - URPreferencesUtil.saveFontColours(previewLabel.getForeground(), previewLabel.getBackground(), settingsPath); + URPreferencesUtil.saveStyleColours(previewLabel.getForeground(), previewLabel.getBackground(), settingsPath); }); return bottomPanel; } - private void setPreviewColour (Color newColour) + private void setPreviewColour (Color newColour, boolean setForeground) { - if(isForeground) + if(setForeground) { previewLabel.setForeground(newColour); } else { - if(newColour != defaultBackground) + if(newColour != targetStyle.getBackground()) previewLabel.setOpaque(true); else previewLabel.setOpaque(false); @@ -158,21 +152,19 @@ protected void fireSaveListeners() public void loadColours() { - Map colourMap = - URPreferencesUtil.loadFontColours(defaultForeground, defaultBackground, settingsPath); + targetStyle = URPreferencesUtil.loadStyle(targetStyle, settingsPath); // defaultBackground = colourMap.get(Constants.KEY_FONT_BACKGROUND); // defaultForeground = colourMap.get(Constants.KEY_FONT_FOREGROUND); - previewLabel.setForeground(colourMap.get(Constants.KEY_FONT_FOREGROUND)); - previewLabel.setOpaque(true); - previewLabel.setBackground(colourMap.get(Constants.KEY_FONT_BACKGROUND)); + setPreviewColour(targetStyle.getForeground(), true); + setPreviewColour(targetStyle.getBackground(), false); } public void stateChanged(ChangeEvent e) { selectedColor = tcc.getColor(); - setPreviewColour(selectedColor); + setPreviewColour(selectedColor, isForeground); } } diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index b375b9a..ffa83be 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -1,12 +1,9 @@ package urChatBasic.frontend.components; -import java.awt.Color; -import java.awt.Component; import java.awt.Font; import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; @@ -16,10 +13,9 @@ import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.swing.*; -import urChatBasic.base.Constants; -import urChatBasic.frontend.LineFormatter; import urChatBasic.frontend.dialogs.ColourDialog; import urChatBasic.backend.utils.URPreferencesUtil; +import urChatBasic.backend.utils.URStyle; public class FontPanel extends JPanel { @@ -42,6 +38,7 @@ public class FontPanel extends JPanel // private String fontType = "New Font:"; // private JLabel fontTypeLabel = new JLabel("New Font:"); private Font defaultFont; + private URStyle targetStyle; // TODO: Add colour picker for foreground and background private List actionListeners = new ArrayList<>(); @@ -52,9 +49,11 @@ public FontPanel(Font defaultFont, Preferences settingsPath, String displayName) { setLayout(new GridBagLayout()); setSettingsPath(settingsPath); + targetStyle = new URStyle(displayName, defaultFont); setDefaultFont(defaultFont); loadFont(); + RESET_BUTTON.addActionListener(new ResetListener()); COLOUR_BUTTON.addActionListener(new ActionListener() { @@ -63,7 +62,7 @@ public void actionPerformed(ActionEvent arg0) { if(colourDialog == null) { - colourDialog = new ColourDialog(displayName, FontPanel.this.getFont(), settingsPath); + colourDialog = new ColourDialog(targetStyle, settingsPath); colourDialog.getColourPanel().addSaveListener(e -> { System.out.println("Save pressed"); @@ -173,7 +172,8 @@ public void resetFont() { public void loadFont() { - setFont(URPreferencesUtil.loadFont(defaultFont, settingsPath), false); + // setFont(URPreferencesUtil.loadStyleFont(defaultFont, settingsPath), false); + setFont(URPreferencesUtil.loadStyle(targetStyle, settingsPath).getFont(), false); } @Override @@ -190,29 +190,13 @@ public void setFont(Font newFont, Boolean saveToSettings) if (getFont() != newFont || saveToSettings) { MAKE_BOLD.setSelected(newFont.isBold()); - if (saveToSettings) - { - settingsPath.putBoolean(Constants.KEY_FONT_BOLD, newFont.isBold()); - } - MAKE_ITALIC.setSelected(newFont.isItalic()); - if (saveToSettings) - { - settingsPath.putBoolean(Constants.KEY_FONT_ITALIC, newFont.isItalic()); - } - FONT_COMBO_BOX.setSelectedItem(newFont.getFamily()); - - if (saveToSettings) - { - settingsPath.put(Constants.KEY_FONT_FAMILY, newFont.getFamily()); - } - SIZES_COMBO_BOX.setSelectedItem(newFont.getSize()); - if (saveToSettings) - { - settingsPath.putInt(Constants.KEY_FONT_SIZE, newFont.getSize()); - } + + targetStyle.setFont(newFont); + if(saveToSettings) + targetStyle.save(settingsPath); revalidate(); repaint(); diff --git a/src/urChatBasic/frontend/dialogs/ColourDialog.java b/src/urChatBasic/frontend/dialogs/ColourDialog.java index 4e2e3a7..6264ee9 100644 --- a/src/urChatBasic/frontend/dialogs/ColourDialog.java +++ b/src/urChatBasic/frontend/dialogs/ColourDialog.java @@ -1,9 +1,9 @@ package urChatBasic.frontend.dialogs; -import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.prefs.Preferences; +import urChatBasic.backend.utils.URStyle; import urChatBasic.base.DialogBase; import urChatBasic.frontend.DriverGUI; import urChatBasic.frontend.components.ColourPanel; @@ -12,15 +12,15 @@ public class ColourDialog extends DialogBase { private ColourPanel colourPanel; - public ColourDialog(String title, Font defaultFont, Preferences settingsPath) + public ColourDialog(URStyle targetStyle, Preferences settingsPath) { - super(DriverGUI.frame, title, true); - initColourDialog(defaultFont, settingsPath); + super(DriverGUI.frame, targetStyle.getName(), true); + initColourDialog(targetStyle, settingsPath); } - public void initColourDialog(Font defaultFont, Preferences settingsPath) + public void initColourDialog(URStyle targetStyle, Preferences settingsPath) { - colourPanel = new ColourPanel(defaultFont, settingsPath); + colourPanel = new ColourPanel(targetStyle, settingsPath); add(colourPanel); setContentPane(colourPanel); From 608fe08f4cc634ee09d8ec0c482df07dcc77f160 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 4 Dec 2023 06:12:06 +1000 Subject: [PATCH 61/78] Continue work to replace fonts with URStyle --- .../backend/utils/URPreferencesUtil.java | 3 +- src/urChatBasic/backend/utils/URStyle.java | 2 +- src/urChatBasic/base/IRCRoomBase.java | 10 ++-- src/urChatBasic/frontend/LineFormatter.java | 10 ++-- src/urChatBasic/frontend/UserGUI.java | 48 ++++++++++++------- .../frontend/components/ColourPanel.java | 4 +- .../frontend/components/FontPanel.java | 36 +++++++++----- .../frontend/dialogs/FontDialog.java | 13 ++--- 8 files changed, 79 insertions(+), 47 deletions(-) diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index efb131d..9ca7be4 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -67,7 +67,8 @@ public static URStyle loadStyle(URStyle defaultStyle, Preferences baseSettingsPa StyleConstants.setBackground(defaultStyle, loadedColours.get(Constants.KEY_FONT_BACKGROUND)); - System.out.println("Loaded: "+defaultStyle.getAttribute("name") + ". Colours - fg: "+URColour.hexEncode(defaultStyle.getForeground()) + " bg: " + URColour.hexEncode(defaultStyle.getBackground())); + System.out.println("Loaded: "+defaultStyle.getAttribute("name") + ". Font: "+loadedFont.getFamily() + + " Colours - fg: "+URColour.hexEncode(defaultStyle.getForeground()) + " bg: " + URColour.hexEncode(defaultStyle.getBackground())); return defaultStyle; } diff --git a/src/urChatBasic/backend/utils/URStyle.java b/src/urChatBasic/backend/utils/URStyle.java index 166d357..1d0d8ad 100644 --- a/src/urChatBasic/backend/utils/URStyle.java +++ b/src/urChatBasic/backend/utils/URStyle.java @@ -28,7 +28,7 @@ public URStyle (String name, Font defaultFont) this.addAttribute("name", name); setFont(defaultFont); setForeground(UIManager.getColor("Label.foreground")); - setBackground(UIManager.getColor("Label.background")); + setBackground(UIManager.getColor("Panel.background")); } public String getName() diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index ba9e889..bf48554 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -171,15 +171,15 @@ private void initRoom() if (null != getServer()) { roomPrefs = gui.getFavouritesPath().node(getServer().getName()).node(roomName); - fontDialog = new FontDialog(gui.getFont(), roomPrefs, roomName); + fontDialog = new FontDialog(gui.getStyle(), roomPrefs, roomName); - lineFormatter = new LineFormatter(getFontPanel().getFont(), gui.getDefaultColours() , getServer(), roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs); } else { roomPrefs = gui.getFavouritesPath().node(roomName); - fontDialog = new FontDialog(gui.getFont(), roomPrefs, roomName); + fontDialog = new FontDialog(gui.getStyle(), roomPrefs, roomName); - lineFormatter = new LineFormatter(getFontPanel().getFont(), gui.getDefaultColours() , null, roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , null, roomPrefs); } setFont(getFontPanel().getFont()); @@ -240,7 +240,7 @@ public FontPanel getFontPanel() public void resetLineFormatter() { - lineFormatter = new LineFormatter(getFontPanel().getFont(), gui.getDefaultColours() , getServer(), roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs); } private void setupMainTextArea() diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 41d78b9..4894ba9 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -45,7 +45,7 @@ public class LineFormatter public URStyle nickStyle; public URStyle myStyle; - public LineFormatter(Font myFont, Map defaultColours, final IRCServerBase server, Preferences formatterPrefs) + public LineFormatter(URStyle baseStyle, final IRCServerBase server, Preferences formatterPrefs) { // TODO: Need to load attributes from formatterPrefs this.formatterPrefs = formatterPrefs; @@ -60,9 +60,9 @@ public LineFormatter(Font myFont, Map defaultColours, final IRCSe myNick = null; } - targetStyle = new URStyle(myNick, myFont); - targetStyle.setBackground(defaultColours.get(Constants.KEY_FONT_FOREGROUND)); - targetStyle.setBackground(defaultColours.get(Constants.KEY_FONT_BACKGROUND)); + targetStyle = new URStyle(myNick, baseStyle.getFont()); + targetStyle.setForeground(baseStyle.getForeground()); + targetStyle.setBackground(baseStyle.getBackground()); // TODO: should we be using something like UIManager // UIManager.getFont for the default fonts isntead? @@ -347,7 +347,7 @@ private void appendString(StyledDocument doc, String insertedString, SimpleAttri insertString(doc, insertedString, style, position); } - private URStyle getStyle(String styleName) + public URStyle getStyle(String styleName) { switch (styleName) { diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index a889bc1..301fd7f 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -18,6 +18,7 @@ import javax.swing.text.AttributeSet; import javax.swing.text.Element; import javax.swing.text.StyledDocument; +import urChatBasic.backend.utils.URStyle; import urChatBasic.backend.utils.URUncaughtExceptionHandler; import urChatBasic.base.Constants; import urChatBasic.base.IRCRoomBase; @@ -77,6 +78,7 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase // Appearance Panel private FontPanel clientFontPanel; + private static URStyle guiStyle; private static final JTextField timeStampField = new JTextField(); private static final JTextPane previewTextArea = new JTextPane(); private static final JScrollPane previewTextScroll = new JScrollPane(previewTextArea); @@ -513,11 +515,6 @@ private void setupLeftOptionsPanel() optionsLeftPanel.add(extrasPanel, BorderLayout.SOUTH); } - public Map getDefaultColours() - { - return urVersionLabel.getColours(); - } - private void setupRightOptionsPanel() { ListSelectionModel listSelectionModel = optionsList.getSelectionModel(); @@ -844,7 +841,7 @@ public Component getListCellRendererComponent(JList list, Object value, int i lafOptions.addActionListener(new ChangeLAFListener()); - clientFontPanel = new FontPanel(getFont(), getProfilePath(), ""); + clientFontPanel = new FontPanel(getStyle(), getProfilePath(), ""); clientFontPanel.setPreferredSize(new Dimension(700, 64)); clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); clientFontPanel.getResetButton().addActionListener(new ResetFontListener()); @@ -900,7 +897,7 @@ public void updatePreviewTextArea() // } // previewTextArea.setFont(clientFontPanel.getFont()); - previewLineFormatter = new LineFormatter(clientFontPanel.getFont(), urVersionLabel.getColours() ,null, getProfilePath()); + previewLineFormatter = new LineFormatter(clientFontPanel.getStyle() ,null, getProfilePath()); if(previewDoc.getLength() <= 0) { @@ -932,7 +929,7 @@ public void mouseClicked(MouseEvent mouseEvent) if (SwingUtilities.isRightMouseButton(mouseEvent) && wordAttributeSet.getAttribute("name") != null) { String styleName = styleLabel.getText(); - FontDialog styleFontDialog = new FontDialog(previewLineFormatter.getStyleAsFont(styleName), getProfilePath(), styleName); + FontDialog styleFontDialog = new FontDialog(previewLineFormatter.getStyle(styleName), getProfilePath(), styleName); styleFontDialog.addSaveListener(arg0 -> { List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); @@ -1143,7 +1140,7 @@ public FavouritesItem(String favServer, String favChannel) this.favChannel = favChannel; settingsPath = getFavouritesPath().node(favServer).node(favChannel); - favFontDialog = new FontDialog(UserGUI.this.getFont(), settingsPath, "Font: " + favChannel); + favFontDialog = new FontDialog(UserGUI.this.getStyle(), settingsPath, "Font: " + favChannel); favFontDialog.addSaveListener(new SaveChannelFontListener()); createPopUp(); } @@ -1216,7 +1213,7 @@ public void actionPerformed(ActionEvent arg0) if (favouritesList.getSelectedIndex() > -1) { FavouritesItem tempItem = favouritesListModel.elementAt(favouritesList.getSelectedIndex()); - tempItem.favFontDialog.getFontPanel().loadFont(); + tempItem.favFontDialog.getFontPanel().loadStyle(); tempItem.favFontDialog.setVisible(true); } } @@ -1607,7 +1604,7 @@ public void getClientSettings(boolean loadWindowSettings) logClientText.setSelected( getProfilePath().getBoolean(Constants.KEY_LOG_CLIENT_TEXT, Constants.DEFAULT_LOG_CLIENT_TEXT)); - clientFontPanel.loadFont(); + clientFontPanel.loadStyle(); timeStampField.setText( getProfilePath().get(Constants.KEY_TIME_STAMP_FORMAT, Constants.DEFAULT_TIME_STAMP_FORMAT) @@ -1862,7 +1859,7 @@ public void actionPerformed(ActionEvent arg0) { FavouritesItem favouriteItem = favouritesList.getModel().getElementAt(index); favouriteItem.favFontDialog.getFontPanel().setDefaultFont(clientFontPanel.getFont()); - favouriteItem.favFontDialog.getFontPanel().loadFont(); + favouriteItem.favFontDialog.getFontPanel().loadStyle(); } previewLineFormatter.setFont(previewTextArea.getStyledDocument(), clientFontPanel.getFont()); @@ -1879,7 +1876,7 @@ public void actionPerformed(ActionEvent arg0) getProfilePath().putBoolean(Constants.KEY_FONT_ITALIC, Constants.DEFAULT_FONT_GENERAL.isItalic()); getProfilePath().putInt(Constants.KEY_FONT_SIZE, Constants.DEFAULT_FONT_GENERAL.getSize()); - clientFontPanel.loadFont(); + clientFontPanel.loadStyle(); clientFontPanel.getSaveButton().doClick(); } @@ -1929,15 +1926,17 @@ public void run() }); } - @Override - public Font getFont() + public URStyle getStyle() { if (clientFontPanel != null) { - return clientFontPanel.getFont(); + return clientFontPanel.getStyle(); } - return super.getFont(); + // Create the default style + URStyle newStyle = new URStyle(profileName, getFont()); + guiStyle = newStyle; + return guiStyle; } private LookAndFeelInfo getLAF(String lafClassName) @@ -1956,6 +1955,10 @@ private LookAndFeelInfo getLAF(String lafClassName) private void setNewLAF(String newLAFname) { + Color previousDefaultForeground = UIManager.getColor("Label.foreground"); + Color previousDefaultBackground = UIManager.getColor("Panel.background"); + Font previousDefaultFont = getFont(); + // System.out.println("Setting to "+newLAFname); boolean flatLafAvailable = false; try @@ -1991,6 +1994,15 @@ private void setNewLAF(String newLAFname) // Required because it doesn't pickup the default ui tabbedPane.setUI((new JTabbedPane()).getUI()); + guiStyle.setFont(clientFontPanel.getFont()); + + // reset the defaults on the guiStyle if they were already at the default + if(previousDefaultForeground == guiStyle.getForeground()) + guiStyle.setForeground(UIManager.getColor("Label.foreground")); + + if(previousDefaultBackground == guiStyle.getBackground()) + guiStyle.setBackground(UIManager.getColor("Panel.background")); + SwingUtilities.updateComponentTreeUI(DriverGUI.frame); updateExtras(); // DriverGUI.frame.dispose(); @@ -2000,6 +2012,8 @@ private void setNewLAF(String newLAFname) // Update the fonts and popup menus - these aren't under the component tree private void updateExtras() { + clientFontPanel.setStyle(guiStyle); + for (int index = 0; index < tabbedPane.getTabCount(); index++) { Component tab = tabbedPane.getComponentAt(index); diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index 0495002..d458ba8 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -107,7 +107,9 @@ public JPanel createBottomPanel() }); addSaveListener(e -> { - URPreferencesUtil.saveStyleColours(previewLabel.getForeground(), previewLabel.getBackground(), settingsPath); + // TODO: Don't save colours unless it's not the default? + // URPreferencesUtil.saveStyleColours(previewLabel.getForeground(), previewLabel.getBackground(), settingsPath); + URPreferencesUtil.saveStyle(targetStyle, settingsPath); }); return bottomPanel; diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index ffa83be..61092fb 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -37,7 +37,7 @@ public class FontPanel extends JPanel protected ColourDialog colourDialog = null; // private String fontType = "New Font:"; // private JLabel fontTypeLabel = new JLabel("New Font:"); - private Font defaultFont; + private URStyle defaultStyle; private URStyle targetStyle; // TODO: Add colour picker for foreground and background @@ -45,13 +45,13 @@ public class FontPanel extends JPanel private Preferences settingsPath; - public FontPanel(Font defaultFont, Preferences settingsPath, String displayName) + public FontPanel(URStyle defaultStyle, Preferences settingsPath, String displayName) { setLayout(new GridBagLayout()); setSettingsPath(settingsPath); - targetStyle = new URStyle(displayName, defaultFont); - setDefaultFont(defaultFont); - loadFont(); + targetStyle = new URStyle(displayName, defaultStyle.getFont()); + this.defaultStyle = defaultStyle; + setDefaultFont(defaultStyle.getFont()); RESET_BUTTON.addActionListener(new ResetListener()); @@ -148,8 +148,14 @@ public JButton getResetButton() public void setDefaultFont(Font f) { - defaultFont = f; - loadFont(); + // defaultFont = f; + defaultStyle.setFont(f); + loadStyle(); + } + + public URStyle getStyle() + { + return targetStyle; } // Deletes the saved font, then loads the "default" font. @@ -158,7 +164,7 @@ public void setDefaultFont(Font f) public void resetFont() { try { - for (String key : settingsPath.keys()) { + for (String key : settingsPath.node(targetStyle.getName()).keys()) { settingsPath.remove(key); } } catch (BackingStoreException e) @@ -167,13 +173,14 @@ public void resetFont() { e.printStackTrace(); } - loadFont(); + loadStyle(); } - public void loadFont() + public void loadStyle() { // setFont(URPreferencesUtil.loadStyleFont(defaultFont, settingsPath), false); - setFont(URPreferencesUtil.loadStyle(targetStyle, settingsPath).getFont(), false); + setStyle(URPreferencesUtil.loadStyle(targetStyle, settingsPath)); + // setFont(URPreferencesUtil.loadStyle(targetStyle, settingsPath).getFont(), false); } @Override @@ -185,6 +192,13 @@ public void setFont(Font f) TEXT_PREVIEW.setFont(f); } + public void setStyle(URStyle newStyle) + { + targetStyle = newStyle; + + setFont(targetStyle.getFont()); + } + public void setFont(Font newFont, Boolean saveToSettings) { if (getFont() != newFont || saveToSettings) diff --git a/src/urChatBasic/frontend/dialogs/FontDialog.java b/src/urChatBasic/frontend/dialogs/FontDialog.java index 5ab3f55..0b2c690 100644 --- a/src/urChatBasic/frontend/dialogs/FontDialog.java +++ b/src/urChatBasic/frontend/dialogs/FontDialog.java @@ -5,6 +5,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.prefs.Preferences; +import urChatBasic.backend.utils.URStyle; import urChatBasic.base.DialogBase; import urChatBasic.frontend.DriverGUI; import urChatBasic.frontend.components.FontPanel; @@ -14,21 +15,21 @@ public class FontDialog extends DialogBase private String title = "Default Font"; private FontPanel fontPanel; - public FontDialog(Font defaultFont, Preferences settingsPath, String title) + public FontDialog(URStyle defaultStyle, Preferences settingsPath, String title) { super(DriverGUI.frame, title, true); this.title = title; - initFontDialog(defaultFont, settingsPath); + initFontDialog(defaultStyle, settingsPath); } - public void initFontDialog(Font defaultFont, Preferences settingsPath) + public void initFontDialog(URStyle defaultStyle, Preferences settingsPath) { setSize(600, 100); setResizable(false); setMaximumSize(new Dimension(600, 100)); setLocationRelativeTo(super.getParent()); - fontPanel = new FontPanel(defaultFont, settingsPath, title); + fontPanel = new FontPanel(defaultStyle, settingsPath, title); add(fontPanel); } @@ -42,7 +43,7 @@ public FontPanel getFontPanel() public void setVisible(boolean b) { setLocationRelativeTo(super.getParent()); - fontPanel.loadFont(); + fontPanel.loadStyle(); super.setVisible(b); } @@ -62,7 +63,7 @@ public class ShowFontDialog implements ActionListener @Override public void actionPerformed(ActionEvent arg0) { - fontPanel.loadFont(); + fontPanel.loadStyle(); FontDialog.this.setVisible(true); } } From 3da9f924f75a8016d10014dc939e3fce8ee68427 Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 5 Dec 2023 06:31:13 +1000 Subject: [PATCH 62/78] Continue work, now on getting the colours working.. --- .../backend/utils/URPreferencesUtil.java | 74 +++++++++++++------ src/urChatBasic/base/Constants.java | 4 +- src/urChatBasic/frontend/UserGUI.java | 13 +++- .../frontend/components/ColourPanel.java | 5 +- .../frontend/components/FontPanel.java | 16 +--- 5 files changed, 73 insertions(+), 39 deletions(-) diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index 9ca7be4..0c9d2f6 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; +import javax.swing.UIManager; import javax.swing.text.StyleConstants; import urChatBasic.base.Constants; import urChatBasic.frontend.utils.URColour; @@ -27,14 +28,14 @@ public static Font loadStyleFont(Font defaultFont, Preferences settingsPath) return savedFont; } - public static Map loadStyleColours(URStyle defaultStyle, Preferences settingsPath) + public static Map loadStyleColours(URStyle targetStyle, Preferences settingsPath) { Map colourMap = new HashMap(); - colourMap.put(Constants.KEY_FONT_FOREGROUND, defaultStyle.getForeground()); - colourMap.put(Constants.KEY_FONT_BACKGROUND, defaultStyle.getBackground()); + colourMap.put(Constants.KEY_FONT_FOREGROUND, targetStyle.getForeground()); + colourMap.put(Constants.KEY_FONT_BACKGROUND, targetStyle.getBackground()); - String loadedForeground = settingsPath.get(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(defaultStyle.getForeground())); - String loadedBackground = settingsPath.get(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(defaultStyle.getBackground())); + String loadedForeground = settingsPath.get(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(targetStyle.getForeground())); + String loadedBackground = settingsPath.get(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(targetStyle.getBackground())); colourMap.replace(Constants.KEY_FONT_FOREGROUND, URColour.hexDecode(loadedForeground)); colourMap.replace(Constants.KEY_FONT_BACKGROUND, URColour.hexDecode(loadedBackground)); @@ -42,35 +43,52 @@ public static Map loadStyleColours(URStyle defaultStyle, Preferen return colourMap; } - public static URStyle loadStyle(URStyle defaultStyle, Preferences baseSettingsPath) + public static URStyle loadStyle(URStyle targetStyle, Preferences baseSettingsPath) { - Preferences stylePrefPath = baseSettingsPath.node(defaultStyle.getAttribute("name").toString()); + Preferences stylePrefPath = baseSettingsPath.node(targetStyle.getAttribute("name").toString()); System.out.println("Load Style Path: " + stylePrefPath.toString()); - Font loadedFont = loadStyleFont(defaultStyle.getFont(), stylePrefPath); + Font loadedFont = loadStyleFont(targetStyle.getFont(), stylePrefPath); // LineFormatter.getStyleAsFont(defaultStyle); - Map loadedColours = loadStyleColours(defaultStyle, stylePrefPath); + Map loadedColours = loadStyleColours(targetStyle, stylePrefPath); // LineFormatter.getStyleColours(defaultStyle); - StyleConstants.setFontFamily(defaultStyle, + StyleConstants.setFontFamily(targetStyle, loadedFont.getFamily()); - StyleConstants.setFontSize(defaultStyle, + StyleConstants.setFontSize(targetStyle, loadedFont.getSize()); - StyleConstants.setBold(defaultStyle, + StyleConstants.setBold(targetStyle, loadedFont.isBold()); - StyleConstants.setItalic(defaultStyle, + StyleConstants.setItalic(targetStyle, loadedFont.isItalic()); - StyleConstants.setForeground(defaultStyle, loadedColours.get(Constants.KEY_FONT_FOREGROUND)); + StyleConstants.setForeground(targetStyle, loadedColours.get(Constants.KEY_FONT_FOREGROUND)); + + StyleConstants.setBackground(targetStyle, loadedColours.get(Constants.KEY_FONT_BACKGROUND)); - StyleConstants.setBackground(defaultStyle, loadedColours.get(Constants.KEY_FONT_BACKGROUND)); + // System.out.println("Loaded: "+targetStyle.getAttribute("name") + ". Font: "+loadedFont.getFamily() + + // " Colours - fg: "+URColour.hexEncode(targetStyle.getForeground()) + " bg: " + URColour.hexEncode(targetStyle.getBackground())); - System.out.println("Loaded: "+defaultStyle.getAttribute("name") + ". Font: "+loadedFont.getFamily() + - " Colours - fg: "+URColour.hexEncode(defaultStyle.getForeground()) + " bg: " + URColour.hexEncode(defaultStyle.getBackground())); + return targetStyle; + } - return defaultStyle; + public static void deleteStyleFont(URStyle targetStyle, Preferences baseSettingsPath) + { + Preferences settingsPath = baseSettingsPath.node(targetStyle.getName()); + try + { + System.out.println("Removing font keys: " + settingsPath.absolutePath()); + settingsPath.remove(Constants.KEY_FONT_BOLD); + settingsPath.remove(Constants.KEY_FONT_ITALIC); + settingsPath.remove(Constants.KEY_FONT_FAMILY); + settingsPath.remove(Constants.KEY_FONT_SIZE); + } catch (Exception e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } } public static void saveStyle(URStyle targetStyle, Preferences baseSettingsPath) @@ -88,15 +106,29 @@ public static void saveStyle(URStyle targetStyle, Preferences baseSettingsPath) */ private static void saveStyleFont(Font newFont, Preferences settingsPath) { + // TODO: Don't safe if it's the default font settingsPath.putBoolean(Constants.KEY_FONT_BOLD, newFont.isBold()); settingsPath.putBoolean(Constants.KEY_FONT_ITALIC, newFont.isItalic()); settingsPath.put(Constants.KEY_FONT_FAMILY, newFont.getFamily()); settingsPath.putInt(Constants.KEY_FONT_SIZE, newFont.getSize()); } - private static void saveStyleColours(Color newForeground, Color newBackground, Preferences settingsPath) + private static void saveStyleColours(Color foreground, Color background, Preferences settingsPath) { - settingsPath.put(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(newForeground)); - settingsPath.put(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(newBackground)); + // Don't save if it's the default colours + Color defaultForeground = UIManager.getColor("Label.foreground"); + Color defaultBackground = UIManager.getColor("Panel.background"); + + if(URColour.hexEncode(defaultForeground).equals(URColour.hexEncode(foreground))) + { + settingsPath.put(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(foreground)); + System.out.println("Didn't save. It's already default colours."); + } + + if(URColour.hexEncode(defaultBackground).equals(URColour.hexEncode(background))) + { + settingsPath.put(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(background)); + System.out.println("Didn't save. It's already default colours."); + } } } diff --git a/src/urChatBasic/base/Constants.java b/src/urChatBasic/base/Constants.java index 724491a..5de1414 100644 --- a/src/urChatBasic/base/Constants.java +++ b/src/urChatBasic/base/Constants.java @@ -19,9 +19,7 @@ /** * Used to store constants that are the same and do not change often. These are things used commonly * across the [front,back]end - * - * @author goofybud16 - * + * */ public class Constants { diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 301fd7f..4fe6f84 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -874,7 +874,7 @@ public void keyReleased(KeyEvent e) { // private static final JButton mediumStyleFontLabel = new JButton("Medium Priority Text Font"); // private static final JButton highStyleFontLabel = new JButton("High Priority Text Font"); - addToPanel(appearancePanel, clientFontPanel, "Global Font", null); + addToPanel(appearancePanel, clientFontPanel, "Profile Font", null); addToPanel(appearancePanel, timeStampField, "Timestamp Format", Size.MEDIUM); addToPanel(appearancePanel, previewTextScroll, "Font Preview", null); @@ -1663,6 +1663,7 @@ public void removeClientSetting(String node, String key) @Override public void cleanUpSettings() { + // TODO: Clean up all nodes if they have empty keys Constants.LOGGER.log(Level.INFO, "Cleaning up settings"); try { @@ -1676,6 +1677,14 @@ public void cleanUpSettings() } } } + + for (String profileNode : getProfilePath().childrenNames()) + { + if (getProfilePath().node(profileNode).keys().length == 0) + { + getProfilePath().node(profileNode).removeNode(); + } + } } catch (BackingStoreException e) { Constants.LOGGER.log(Level.WARNING, e.getLocalizedMessage()); @@ -1934,7 +1943,7 @@ public URStyle getStyle() } // Create the default style - URStyle newStyle = new URStyle(profileName, getFont()); + URStyle newStyle = new URStyle("", getFont()); guiStyle = newStyle; return guiStyle; } diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index d458ba8..d425d3d 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -28,10 +28,11 @@ public class ColourPanel extends JPanel implements ChangeListener JButton saveButton; JLabel previewLabel; - public ColourPanel(URStyle targetStyle, Preferences settingsPath) + public ColourPanel(URStyle defaultStyle, Preferences settingsPath) { super(new BorderLayout()); this.settingsPath = settingsPath; + targetStyle = defaultStyle; saveButton = new JButton("Apply & Save"); previewLabel = new JLabel("Preview Text"); previewLabel.setFont(targetStyle.getFont()); @@ -120,6 +121,7 @@ private void setPreviewColour (Color newColour, boolean setForeground) if(setForeground) { previewLabel.setForeground(newColour); + targetStyle.setForeground(newColour); } else { if(newColour != targetStyle.getBackground()) @@ -128,6 +130,7 @@ private void setPreviewColour (Color newColour, boolean setForeground) previewLabel.setOpaque(false); previewLabel.setBackground(newColour); + targetStyle.setBackground(newColour); } } diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 61092fb..256e50b 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -65,6 +65,7 @@ public void actionPerformed(ActionEvent arg0) colourDialog = new ColourDialog(targetStyle, settingsPath); colourDialog.getColourPanel().addSaveListener(e -> { + URPreferencesUtil.saveStyle(targetStyle, settingsPath); System.out.println("Save pressed"); }); } @@ -159,19 +160,10 @@ public URStyle getStyle() } // Deletes the saved font, then loads the "default" font. - // The default font for a channel is the Global Font, the default font + // The default font for a channel is the Profile Font, the default font // the UserGUI is Constants.DEFAULT_FONT public void resetFont() { - try - { - for (String key : settingsPath.node(targetStyle.getName()).keys()) { - settingsPath.remove(key); - } - } catch (BackingStoreException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } + URPreferencesUtil.deleteStyleFont(targetStyle, settingsPath); loadStyle(); } @@ -196,7 +188,7 @@ public void setStyle(URStyle newStyle) { targetStyle = newStyle; - setFont(targetStyle.getFont()); + setFont(targetStyle.getFont(), false); } public void setFont(Font newFont, Boolean saveToSettings) From 7c5dbbf3c384b2dfc8db237dc9e9a05f579cde23 Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 6 Dec 2023 06:30:40 +1000 Subject: [PATCH 63/78] Some refactoring to help with consistentcy between naming in the ColourPanel and the FontPanel. --- .../backend/utils/URPreferencesUtil.java | 35 +++++++++++++++---- src/urChatBasic/base/IRCRoomBase.java | 4 +-- src/urChatBasic/frontend/UserGUI.java | 6 ++-- .../frontend/components/ColourPanel.java | 24 ++++++------- .../frontend/components/FontPanel.java | 7 ++-- .../frontend/dialogs/ColourDialog.java | 12 ++++--- .../frontend/dialogs/FontDialog.java | 11 +++--- 7 files changed, 59 insertions(+), 40 deletions(-) diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index 0c9d2f6..f50c62c 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -12,6 +12,12 @@ public class URPreferencesUtil { + /** + * Uses the defaultFont for the returned font if there is no font saved. + * @param defaultFont + * @param settingsPath + * @return + */ public static Font loadStyleFont(Font defaultFont, Preferences settingsPath) { Font savedFont = defaultFont; @@ -28,14 +34,20 @@ public static Font loadStyleFont(Font defaultFont, Preferences settingsPath) return savedFont; } - public static Map loadStyleColours(URStyle targetStyle, Preferences settingsPath) + /** + * Uses the defaultStyle for the returned colours if there aren't any colours saved. + * @param defaultStyle + * @param settingsPath + * @return + */ + public static Map loadStyleColours(URStyle defaultStyle, Preferences settingsPath) { Map colourMap = new HashMap(); - colourMap.put(Constants.KEY_FONT_FOREGROUND, targetStyle.getForeground()); - colourMap.put(Constants.KEY_FONT_BACKGROUND, targetStyle.getBackground()); + colourMap.put(Constants.KEY_FONT_FOREGROUND, defaultStyle.getForeground()); + colourMap.put(Constants.KEY_FONT_BACKGROUND, defaultStyle.getBackground()); - String loadedForeground = settingsPath.get(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(targetStyle.getForeground())); - String loadedBackground = settingsPath.get(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(targetStyle.getBackground())); + String loadedForeground = settingsPath.get(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(defaultStyle.getForeground())); + String loadedBackground = settingsPath.get(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(defaultStyle.getBackground())); colourMap.replace(Constants.KEY_FONT_FOREGROUND, URColour.hexDecode(loadedForeground)); colourMap.replace(Constants.KEY_FONT_BACKGROUND, URColour.hexDecode(loadedBackground)); @@ -113,6 +125,13 @@ private static void saveStyleFont(Font newFont, Preferences settingsPath) settingsPath.putInt(Constants.KEY_FONT_SIZE, newFont.getSize()); } + /** + * Removes the saved colours if they've been set to the default, this ensures we're not accidentally + * overriding the default theme colours when the theme is changed. + * @param foreground + * @param background + * @param settingsPath + */ private static void saveStyleColours(Color foreground, Color background, Preferences settingsPath) { // Don't save if it's the default colours @@ -121,14 +140,16 @@ private static void saveStyleColours(Color foreground, Color background, Prefere if(URColour.hexEncode(defaultForeground).equals(URColour.hexEncode(foreground))) { + settingsPath.remove(Constants.KEY_FONT_FOREGROUND); + } else { settingsPath.put(Constants.KEY_FONT_FOREGROUND, URColour.hexEncode(foreground)); - System.out.println("Didn't save. It's already default colours."); } if(URColour.hexEncode(defaultBackground).equals(URColour.hexEncode(background))) { + settingsPath.remove(Constants.KEY_FONT_BACKGROUND); + } else { settingsPath.put(Constants.KEY_FONT_BACKGROUND, URColour.hexEncode(background)); - System.out.println("Didn't save. It's already default colours."); } } } diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index bf48554..6c1c7bb 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -171,13 +171,13 @@ private void initRoom() if (null != getServer()) { roomPrefs = gui.getFavouritesPath().node(getServer().getName()).node(roomName); - fontDialog = new FontDialog(gui.getStyle(), roomPrefs, roomName); + fontDialog = new FontDialog(roomName, gui.getStyle(), roomPrefs); lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs); } else { roomPrefs = gui.getFavouritesPath().node(roomName); - fontDialog = new FontDialog(gui.getStyle(), roomPrefs, roomName); + fontDialog = new FontDialog(roomName, gui.getStyle(), roomPrefs); lineFormatter = new LineFormatter(getFontPanel().getStyle() , null, roomPrefs); } diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 4fe6f84..ae37720 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -841,7 +841,7 @@ public Component getListCellRendererComponent(JList list, Object value, int i lafOptions.addActionListener(new ChangeLAFListener()); - clientFontPanel = new FontPanel(getStyle(), getProfilePath(), ""); + clientFontPanel = new FontPanel("", getStyle(), getProfilePath()); clientFontPanel.setPreferredSize(new Dimension(700, 64)); clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); clientFontPanel.getResetButton().addActionListener(new ResetFontListener()); @@ -929,7 +929,7 @@ public void mouseClicked(MouseEvent mouseEvent) if (SwingUtilities.isRightMouseButton(mouseEvent) && wordAttributeSet.getAttribute("name") != null) { String styleName = styleLabel.getText(); - FontDialog styleFontDialog = new FontDialog(previewLineFormatter.getStyle(styleName), getProfilePath(), styleName); + FontDialog styleFontDialog = new FontDialog(styleName, previewLineFormatter.getStyle(styleName), getProfilePath()); styleFontDialog.addSaveListener(arg0 -> { List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); @@ -1140,7 +1140,7 @@ public FavouritesItem(String favServer, String favChannel) this.favChannel = favChannel; settingsPath = getFavouritesPath().node(favServer).node(favChannel); - favFontDialog = new FontDialog(UserGUI.this.getStyle(), settingsPath, "Font: " + favChannel); + favFontDialog = new FontDialog("Font: " + favChannel, UserGUI.this.getStyle(), settingsPath); favFontDialog.addSaveListener(new SaveChannelFontListener()); createPopUp(); } diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index d425d3d..9e13fb3 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -3,14 +3,11 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.HashMap; -import java.util.Map; import java.util.prefs.Preferences; import javax.swing.*; import javax.swing.event.*; import urChatBasic.backend.utils.URPreferencesUtil; import urChatBasic.backend.utils.URStyle; -import urChatBasic.base.Constants; import urChatBasic.frontend.utils.URColour; /* ColorChooserDemo.java requires no other files. */ @@ -22,20 +19,22 @@ public class ColourPanel extends JPanel implements ChangeListener protected JColorChooser tcc; public Color selectedColor; private URStyle targetStyle; + private URStyle defaultStyle; private Preferences settingsPath; private JPanel bottomPanel; private boolean isForeground = true; JButton saveButton; JLabel previewLabel; - public ColourPanel(URStyle defaultStyle, Preferences settingsPath) + public ColourPanel(String styleName, URStyle defaultStyle, Preferences settingsPath) { super(new BorderLayout()); - this.settingsPath = settingsPath; - targetStyle = defaultStyle; saveButton = new JButton("Apply & Save"); previewLabel = new JLabel("Preview Text"); - previewLabel.setFont(targetStyle.getFont()); + this.settingsPath = settingsPath; + this.defaultStyle = defaultStyle; + targetStyle = (URStyle) defaultStyle.clone(); + loadStyle(); bottomPanel = createBottomPanel(); // Set up color chooser for setting text color @@ -87,10 +86,9 @@ public JPanel createBottomPanel() }); resetButton.addActionListener(e -> { - if (isForeground) - setPreviewColour(targetStyle.getForeground(), isForeground); - else - setPreviewColour(targetStyle.getBackground(), isForeground); + previewLabel.setFont(defaultStyle.getFont()); + setPreviewColour(defaultStyle.getForeground(), true); + setPreviewColour(defaultStyle.getBackground(), false); }); autoColour.addActionListener(e -> { @@ -155,13 +153,13 @@ protected void fireSaveListeners() } } - public void loadColours() + public void loadStyle() { targetStyle = URPreferencesUtil.loadStyle(targetStyle, settingsPath); // defaultBackground = colourMap.get(Constants.KEY_FONT_BACKGROUND); // defaultForeground = colourMap.get(Constants.KEY_FONT_FOREGROUND); - + previewLabel.setFont(targetStyle.getFont()); setPreviewColour(targetStyle.getForeground(), true); setPreviewColour(targetStyle.getBackground(), false); } diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 256e50b..e6658d0 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -10,7 +10,6 @@ import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.List; -import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.swing.*; import urChatBasic.frontend.dialogs.ColourDialog; @@ -45,11 +44,11 @@ public class FontPanel extends JPanel private Preferences settingsPath; - public FontPanel(URStyle defaultStyle, Preferences settingsPath, String displayName) + public FontPanel(String styleName, URStyle defaultStyle, Preferences settingsPath) { setLayout(new GridBagLayout()); setSettingsPath(settingsPath); - targetStyle = new URStyle(displayName, defaultStyle.getFont()); + targetStyle = new URStyle(styleName, defaultStyle.getFont()); this.defaultStyle = defaultStyle; setDefaultFont(defaultStyle.getFont()); @@ -62,7 +61,7 @@ public void actionPerformed(ActionEvent arg0) { if(colourDialog == null) { - colourDialog = new ColourDialog(targetStyle, settingsPath); + colourDialog = new ColourDialog(styleName, defaultStyle, settingsPath); colourDialog.getColourPanel().addSaveListener(e -> { URPreferencesUtil.saveStyle(targetStyle, settingsPath); diff --git a/src/urChatBasic/frontend/dialogs/ColourDialog.java b/src/urChatBasic/frontend/dialogs/ColourDialog.java index 6264ee9..5c63271 100644 --- a/src/urChatBasic/frontend/dialogs/ColourDialog.java +++ b/src/urChatBasic/frontend/dialogs/ColourDialog.java @@ -10,17 +10,19 @@ public class ColourDialog extends DialogBase { + private String styleName = "Default Font"; private ColourPanel colourPanel; - public ColourDialog(URStyle targetStyle, Preferences settingsPath) + public ColourDialog(String styleName, URStyle defaultStyle, Preferences settingsPath) { - super(DriverGUI.frame, targetStyle.getName(), true); - initColourDialog(targetStyle, settingsPath); + super(DriverGUI.frame, defaultStyle.getName(), true); + this.styleName = styleName; + initColourDialog(defaultStyle, settingsPath); } - public void initColourDialog(URStyle targetStyle, Preferences settingsPath) + public void initColourDialog(URStyle defaultStyle, Preferences settingsPath) { - colourPanel = new ColourPanel(targetStyle, settingsPath); + colourPanel = new ColourPanel(styleName, defaultStyle, settingsPath); add(colourPanel); setContentPane(colourPanel); diff --git a/src/urChatBasic/frontend/dialogs/FontDialog.java b/src/urChatBasic/frontend/dialogs/FontDialog.java index 0b2c690..e880b8a 100644 --- a/src/urChatBasic/frontend/dialogs/FontDialog.java +++ b/src/urChatBasic/frontend/dialogs/FontDialog.java @@ -1,7 +1,6 @@ package urChatBasic.frontend.dialogs; import java.awt.Dimension; -import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.prefs.Preferences; @@ -12,13 +11,13 @@ public class FontDialog extends DialogBase { - private String title = "Default Font"; + private String styleName = "Default Font"; private FontPanel fontPanel; - public FontDialog(URStyle defaultStyle, Preferences settingsPath, String title) + public FontDialog(String styleName, URStyle defaultStyle, Preferences settingsPath) { - super(DriverGUI.frame, title, true); - this.title = title; + super(DriverGUI.frame, styleName, true); + this.styleName = styleName; initFontDialog(defaultStyle, settingsPath); } @@ -29,7 +28,7 @@ public void initFontDialog(URStyle defaultStyle, Preferences settingsPath) setMaximumSize(new Dimension(600, 100)); setLocationRelativeTo(super.getParent()); - fontPanel = new FontPanel(defaultStyle, settingsPath, title); + fontPanel = new FontPanel(styleName, defaultStyle, settingsPath); add(fontPanel); } From 0e84f74aeab412f2300e5904fda9e0ed9f4d23d7 Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 6 Dec 2023 06:55:20 +1000 Subject: [PATCH 64/78] Works? --- src/urChatBasic/frontend/LineFormatter.java | 3 ++- src/urChatBasic/frontend/components/ColourPanel.java | 1 + src/urChatBasic/frontend/components/FontPanel.java | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 4894ba9..e08316e 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -194,7 +194,8 @@ public URStyle channelStyle() StyleConstants.setBold(tempStyle, true); StyleConstants.setUnderline(tempStyle, true); - tempStyle.load(formatterPrefs); + // tempStyle.load(formatterPrefs); + tempStyle = URPreferencesUtil.loadStyle(tempStyle, formatterPrefs); return tempStyle; } diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index 9e13fb3..b04ffbd 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -159,6 +159,7 @@ public void loadStyle() // defaultBackground = colourMap.get(Constants.KEY_FONT_BACKGROUND); // defaultForeground = colourMap.get(Constants.KEY_FONT_FOREGROUND); + // TODO: Should also be underlined etc.. previewLabel.setFont(targetStyle.getFont()); setPreviewColour(targetStyle.getForeground(), true); setPreviewColour(targetStyle.getBackground(), false); diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index e6658d0..f3e5abc 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -64,7 +64,7 @@ public void actionPerformed(ActionEvent arg0) colourDialog = new ColourDialog(styleName, defaultStyle, settingsPath); colourDialog.getColourPanel().addSaveListener(e -> { - URPreferencesUtil.saveStyle(targetStyle, settingsPath); + // URPreferencesUtil.saveStyle(targetStyle, settingsPath); System.out.println("Save pressed"); }); } From 1ce517ef0e5c367bffdce5d2e3f787532d80c9a9 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 7 Dec 2023 06:30:03 +1000 Subject: [PATCH 65/78] Loading colour is working, but we need a fallback setting path for rooms etc --- .../backend/utils/URPreferencesUtil.java | 6 ++++ src/urChatBasic/base/IRCRoomBase.java | 6 ++-- src/urChatBasic/frontend/LineFormatter.java | 7 ++++- src/urChatBasic/frontend/UserGUI.java | 4 +-- .../frontend/components/ColourPanel.java | 14 ++++------ .../frontend/components/FontPanel.java | 20 ++++--------- .../frontend/dialogs/ColourDialog.java | 28 +++++++------------ 7 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index f50c62c..9dc5cb3 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -55,6 +55,12 @@ public static Map loadStyleColours(URStyle defaultStyle, Preferen return colourMap; } + /** + * TODO: Add a fallbackSettingsPath in order to have somewhere else to load the targetStyle from if the baseSettingsPath doesn't exist. + * @param targetStyle + * @param baseSettingsPath + * @return + */ public static URStyle loadStyle(URStyle targetStyle, Preferences baseSettingsPath) { Preferences stylePrefPath = baseSettingsPath.node(targetStyle.getAttribute("name").toString()); diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 6c1c7bb..b1182bd 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -173,13 +173,13 @@ private void initRoom() roomPrefs = gui.getFavouritesPath().node(getServer().getName()).node(roomName); fontDialog = new FontDialog(roomName, gui.getStyle(), roomPrefs); - lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs, gui.getProfilePath()); } else { roomPrefs = gui.getFavouritesPath().node(roomName); fontDialog = new FontDialog(roomName, gui.getStyle(), roomPrefs); - lineFormatter = new LineFormatter(getFontPanel().getStyle() , null, roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , null, roomPrefs, gui.getProfilePath()); } setFont(getFontPanel().getFont()); @@ -240,7 +240,7 @@ public FontPanel getFontPanel() public void resetLineFormatter() { - lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs, gui.getProfilePath()); } private void setupMainTextArea() diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index e08316e..7cf50b2 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -40,16 +40,21 @@ public class LineFormatter private Color myBackground; private IRCServerBase myServer; private Preferences formatterPrefs; + /** + * Used to load the style from, if it doesn't exist in the current formatterPrefs + */ + private Preferences fallbackPreferences; public URStyle timeStyle; public URStyle lineStyle; public URStyle nickStyle; public URStyle myStyle; - public LineFormatter(URStyle baseStyle, final IRCServerBase server, Preferences formatterPrefs) + public LineFormatter(URStyle baseStyle, final IRCServerBase server, Preferences formatterPrefs, Preferences fallbackPreferences) { // TODO: Need to load attributes from formatterPrefs this.formatterPrefs = formatterPrefs; + this.fallbackPreferences = fallbackPreferences; if (null != server) { diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index ae37720..ba4dd1f 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -897,7 +897,7 @@ public void updatePreviewTextArea() // } // previewTextArea.setFont(clientFontPanel.getFont()); - previewLineFormatter = new LineFormatter(clientFontPanel.getStyle() ,null, getProfilePath()); + previewLineFormatter = new LineFormatter(clientFontPanel.getStyle() ,null, getProfilePath(), null); if(previewDoc.getLength() <= 0) { @@ -929,7 +929,7 @@ public void mouseClicked(MouseEvent mouseEvent) if (SwingUtilities.isRightMouseButton(mouseEvent) && wordAttributeSet.getAttribute("name") != null) { String styleName = styleLabel.getText(); - FontDialog styleFontDialog = new FontDialog(styleName, previewLineFormatter.getStyle(styleName), getProfilePath()); + FontDialog styleFontDialog = new FontDialog(styleName, guiStyle, getProfilePath()); styleFontDialog.addSaveListener(arg0 -> { List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index b04ffbd..fbdf28e 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -33,7 +33,7 @@ public ColourPanel(String styleName, URStyle defaultStyle, Preferences settingsP previewLabel = new JLabel("Preview Text"); this.settingsPath = settingsPath; this.defaultStyle = defaultStyle; - targetStyle = (URStyle) defaultStyle.clone(); + targetStyle = new URStyle(styleName, defaultStyle.getFont()); loadStyle(); bottomPanel = createBottomPanel(); @@ -102,13 +102,11 @@ public JPanel createBottomPanel() }); saveButton.addActionListener(e -> { - fireSaveListeners(); - }); - - addSaveListener(e -> { - // TODO: Don't save colours unless it's not the default? - // URPreferencesUtil.saveStyleColours(previewLabel.getForeground(), previewLabel.getBackground(), settingsPath); + // Save the style first URPreferencesUtil.saveStyle(targetStyle, settingsPath); + + // now fire the rest of the save listeners + fireSaveListeners(); }); return bottomPanel; @@ -134,7 +132,6 @@ private void setPreviewColour (Color newColour, boolean setForeground) public void addSaveListener (ActionListener actionListener) { - // saveButton.addActionListener(actionListener); listenerList.add(ActionListener.class, actionListener); } @@ -142,6 +139,7 @@ protected void fireSaveListeners() { Object[] listeners = this.listenerList.getListenerList(); + // Reverse order for(int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { if (this.actionEvent == null) { diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index f3e5abc..8b952d2 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -40,6 +40,10 @@ public class FontPanel extends JPanel private URStyle targetStyle; // TODO: Add colour picker for foreground and background + /** + * TODO: This will be used instead for creating the action listeners: private Map actionList = new HashMap<>(); + * @see ColourPanel.fireSaveListeners() + */ private List actionListeners = new ArrayList<>(); private Preferences settingsPath; @@ -50,7 +54,7 @@ public FontPanel(String styleName, URStyle defaultStyle, Preferences settingsPat setSettingsPath(settingsPath); targetStyle = new URStyle(styleName, defaultStyle.getFont()); this.defaultStyle = defaultStyle; - setDefaultFont(defaultStyle.getFont()); + setDefaultFont(targetStyle.getFont()); RESET_BUTTON.addActionListener(new ResetListener()); @@ -65,7 +69,7 @@ public void actionPerformed(ActionEvent arg0) colourDialog.getColourPanel().addSaveListener(e -> { // URPreferencesUtil.saveStyle(targetStyle, settingsPath); - System.out.println("Save pressed"); + System.out.println("Font Panel says: Save Colour pressed"); }); } @@ -232,18 +236,6 @@ public void addActionListener(JButton targetButton, ActionListener listener) { targetButton.addActionListener(listener); } - // Using reflection - we check to see if the class implements the ActionListener interface - // private static boolean implementsActionListener(Component component) { - // Class[] interfaces = component.getClass().getInterfaces(); - // Class actionListenerClass = ActionListener.class; - - // for (Class iface : interfaces) { - // if (iface == actionListenerClass) { - // return true; - // } - // } - // return false; - // } // Method to retrieve all added listeners public List getActionListeners() { diff --git a/src/urChatBasic/frontend/dialogs/ColourDialog.java b/src/urChatBasic/frontend/dialogs/ColourDialog.java index 5c63271..dbaacee 100644 --- a/src/urChatBasic/frontend/dialogs/ColourDialog.java +++ b/src/urChatBasic/frontend/dialogs/ColourDialog.java @@ -35,7 +35,6 @@ public void initColourDialog(URStyle defaultStyle, Preferences settingsPath) colourPanel.addSaveListener(e -> { ColourDialog.this.setVisible(false); - System.out.println("Set visible false"); }); } @@ -45,31 +44,24 @@ public ColourPanel getColourPanel() } @Override - public void setVisible(boolean b) + public void setVisible(boolean shown) { - setLocationRelativeTo(super.getParent()); + System.out.println("Colour Dialog visible = " + shown); + if (!shown) + colourPanel.loadStyle(); + else + setLocationRelativeTo(super.getParent()); - super.setVisible(b); + super.setVisible(shown); } - // public void addSaveListener(ActionListener newActionListener) - // { - // // fontPanel.getSaveButton().addActionListener(newActionListener); - // fontPanel.addActionListener(fontPanel.getSaveButton(), newActionListener); - // } - - // public void addResetListener(ActionListener newActionListener) - // { - // fontPanel.getResetButton().addActionListener(newActionListener); - // } - - public class ShowColourDialog implements ActionListener + public class HideColourDialog implements ActionListener { - @Override + @Override public void actionPerformed(ActionEvent arg0) { // fontPanel.loadFont(); - ColourDialog.this.setVisible(true); + colourPanel.loadStyle(); } } } From 9492d12c516bb68307fe287e0689d9811c067a2c Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 8 Dec 2023 06:43:39 +1000 Subject: [PATCH 66/78] Improved colour handling. Just need to work on the "default" handling and saving. --- .../backend/utils/URPreferencesUtil.java | 40 ++++- src/urChatBasic/backend/utils/URStyle.java | 37 +++- src/urChatBasic/base/IRCRoomBase.java | 8 +- src/urChatBasic/frontend/LineFormatter.java | 169 +++++++++--------- src/urChatBasic/frontend/UserGUI.java | 153 +++++++++------- .../frontend/components/ColourPanel.java | 11 +- 6 files changed, 254 insertions(+), 164 deletions(-) diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index 9dc5cb3..5d2ba77 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -4,10 +4,12 @@ import java.awt.Font; import java.util.HashMap; import java.util.Map; +import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.swing.UIManager; import javax.swing.text.StyleConstants; import urChatBasic.base.Constants; +import urChatBasic.frontend.DriverGUI; import urChatBasic.frontend.utils.URColour; public class URPreferencesUtil { @@ -61,9 +63,26 @@ public static Map loadStyleColours(URStyle defaultStyle, Preferen * @param baseSettingsPath * @return */ - public static URStyle loadStyle(URStyle targetStyle, Preferences baseSettingsPath) + public static URStyle loadStyle(final URStyle targetStyle, Preferences baseSettingsPath) { - Preferences stylePrefPath = baseSettingsPath.node(targetStyle.getAttribute("name").toString()); + // targetStyle = targetStyle.clone(); + // Default to the profile path node + Preferences stylePrefPath = baseSettingsPath; + try + { + if(baseSettingsPath.nodeExists(targetStyle.getAttribute("name").toString())) + stylePrefPath = baseSettingsPath.node(targetStyle.getAttribute("name").toString()); + else if (DriverGUI.gui != null) + stylePrefPath = DriverGUI.gui.getProfilePath().node(targetStyle.getAttribute("name").toString()); + else + stylePrefPath = baseSettingsPath.node(targetStyle.getAttribute("name").toString()); + } catch (BackingStoreException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + System.out.println("Load Style Path: " + stylePrefPath.toString()); Font loadedFont = loadStyleFont(targetStyle.getFont(), stylePrefPath); // LineFormatter.getStyleAsFont(defaultStyle); @@ -89,7 +108,7 @@ public static URStyle loadStyle(URStyle targetStyle, Preferences baseSettingsPat // System.out.println("Loaded: "+targetStyle.getAttribute("name") + ". Font: "+loadedFont.getFamily() + // " Colours - fg: "+URColour.hexEncode(targetStyle.getForeground()) + " bg: " + URColour.hexEncode(targetStyle.getBackground())); - return targetStyle; + return targetStyle.clone(); } public static void deleteStyleFont(URStyle targetStyle, Preferences baseSettingsPath) @@ -109,6 +128,21 @@ public static void deleteStyleFont(URStyle targetStyle, Preferences baseSettings } } + public static void deleteStyleColours(URStyle targetStyle, Preferences baseSettingsPath) + { + Preferences settingsPath = baseSettingsPath.node(targetStyle.getName()); + try + { + System.out.println("Removing font colours: " + settingsPath.absolutePath()); + settingsPath.remove(Constants.KEY_FONT_FOREGROUND); + settingsPath.remove(Constants.KEY_FONT_BACKGROUND); + } catch (Exception e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + public static void saveStyle(URStyle targetStyle, Preferences baseSettingsPath) { Preferences stylePrefPath = baseSettingsPath.node(targetStyle.getAttribute("name").toString()); diff --git a/src/urChatBasic/backend/utils/URStyle.java b/src/urChatBasic/backend/utils/URStyle.java index 1d0d8ad..5cca6ed 100644 --- a/src/urChatBasic/backend/utils/URStyle.java +++ b/src/urChatBasic/backend/utils/URStyle.java @@ -6,29 +6,41 @@ import javax.swing.UIManager; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; -import urChatBasic.base.Constants; public class URStyle extends SimpleAttributeSet { + // /** + // * Create a URStyle with defaults + // */ + // public URStyle (String name) + // { + // this(name, Constants.DEFAULT_FONT_GENERAL); + // } + /** - * Create a URStyle with defaults + * Create a URStyle based on defaultFont + * @param defaultFont */ - public URStyle (String name) + public URStyle (String name, Font defaultFont) { - this(name, Constants.DEFAULT_FONT_GENERAL); + super(); + this.addAttribute("name", name); + setFont(defaultFont); + setForeground(UIManager.getColor("Label.foreground")); + setBackground(UIManager.getColor("Panel.background")); } /** * Create a URStyle based on defaultFont * @param defaultFont */ - public URStyle (String name, Font defaultFont) + public URStyle (String name, Font defaultFont, Color defaultForeground, Color defaultBackground) { super(); this.addAttribute("name", name); setFont(defaultFont); - setForeground(UIManager.getColor("Label.foreground")); - setBackground(UIManager.getColor("Panel.background")); + setForeground(defaultForeground); + setBackground(defaultBackground); } public String getName() @@ -91,4 +103,15 @@ public void save(Preferences prefPath) { URPreferencesUtil.saveStyle(this, prefPath); } + + public boolean equals (URStyle otherStyle) + { + return getFont().equals(otherStyle.getFont()) && getForeground().equals(otherStyle.getForeground()) && getBackground().equals(otherStyle.getBackground()); + } + + @Override + public URStyle clone () + { + return new URStyle(getName(), getFont(), getForeground(), getBackground()); + } } diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index b1182bd..d64a08b 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -173,13 +173,13 @@ private void initRoom() roomPrefs = gui.getFavouritesPath().node(getServer().getName()).node(roomName); fontDialog = new FontDialog(roomName, gui.getStyle(), roomPrefs); - lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs, gui.getProfilePath()); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs); } else { roomPrefs = gui.getFavouritesPath().node(roomName); fontDialog = new FontDialog(roomName, gui.getStyle(), roomPrefs); - lineFormatter = new LineFormatter(getFontPanel().getStyle() , null, roomPrefs, gui.getProfilePath()); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , null, roomPrefs); } setFont(getFontPanel().getFont()); @@ -240,7 +240,7 @@ public FontPanel getFontPanel() public void resetLineFormatter() { - lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs, gui.getProfilePath()); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs); } private void setupMainTextArea() @@ -521,7 +521,7 @@ public void run() { lineFormatter.formattedDocument(doc, new Date(), fromIRCUser, fromUser, line); - if (lineFormatter.myStyle.getAttribute("name") == lineFormatter.highStyle() + if (lineFormatter.myStyle.getAttribute("name") == lineFormatter.highStyle(true) .getAttribute("name")) { callForAttention(); diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 7cf50b2..2f82411 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -25,7 +25,6 @@ import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; -import urChatBasic.backend.utils.URPreferencesUtil; import urChatBasic.backend.utils.URStyle; import urChatBasic.base.Constants; import urChatBasic.base.IRCServerBase; @@ -40,22 +39,16 @@ public class LineFormatter private Color myBackground; private IRCServerBase myServer; private Preferences formatterPrefs; - /** - * Used to load the style from, if it doesn't exist in the current formatterPrefs - */ - private Preferences fallbackPreferences; public URStyle timeStyle; public URStyle lineStyle; public URStyle nickStyle; public URStyle myStyle; - public LineFormatter(URStyle baseStyle, final IRCServerBase server, Preferences formatterPrefs, Preferences fallbackPreferences) + public LineFormatter(URStyle baseStyle, final IRCServerBase server, Preferences formatterPrefs) { // TODO: Need to load attributes from formatterPrefs this.formatterPrefs = formatterPrefs; - this.fallbackPreferences = fallbackPreferences; - if (null != server) { myNick = server.getNick(); @@ -74,10 +67,10 @@ public LineFormatter(URStyle baseStyle, final IRCServerBase server, Preferences myForeground = targetStyle.getForeground(); myBackground = targetStyle.getBackground(); - timeStyle = defaultStyle(null); - lineStyle = defaultStyle(null); - nickStyle = nickStyle(); - myStyle = myStyle(); + timeStyle = defaultStyle(null, true); + lineStyle = defaultStyle(null, true); + nickStyle = nickStyle(false); + myStyle = myStyle(false); } public void setFont(StyledDocument doc, Font newFont) @@ -87,45 +80,42 @@ public void setFont(StyledDocument doc, Font newFont) updateStyles(doc, 0); } - public URStyle defaultStyle(String name) + public URStyle defaultStyle(String name, boolean load) { if (name == null) name = "defaultStyle"; - - - URStyle defaultStyle = new URStyle(name, targetStyle.getFont()); - defaultStyle.addAttribute("type", "default"); + URStyle tempStyle = new URStyle(name, targetStyle.getFont()); + tempStyle.addAttribute("type", "default"); // get the contrasting colour of the background colour - // StyleConstants.setForeground(defaultStyle, new Color(formatterPrefs.node(name).getInt("font foreground", - // URColour.getContrastColour(UIManager.getColor("Panel.background")).getRGB()))); + // StyleConstants.setForeground(defaultStyle, new Color(formatterPrefs.node(name).getInt("font + // foreground", + // URColour.getContrastColour(UIManager.getColor("Panel.background")).getRGB()))); - StyleConstants.setFontFamily(defaultStyle, targetStyle.getFont().getFamily()); - StyleConstants.setFontSize(defaultStyle, targetStyle.getFont().getSize()); - StyleConstants.setBold(defaultStyle, targetStyle.getFont().isBold()); - StyleConstants.setItalic(defaultStyle, targetStyle.getFont().isItalic()); + StyleConstants.setFontFamily(tempStyle, targetStyle.getFont().getFamily()); + StyleConstants.setFontSize(tempStyle, targetStyle.getFont().getSize()); + StyleConstants.setBold(tempStyle, targetStyle.getFont().isBold()); + StyleConstants.setItalic(tempStyle, targetStyle.getFont().isItalic()); - StyleConstants.setForeground(defaultStyle, myForeground); - StyleConstants.setBackground(defaultStyle, myBackground); + StyleConstants.setForeground(tempStyle, myForeground); + StyleConstants.setBackground(tempStyle, myBackground); - // defaultStyle = loadFontStyle(name, defaultStyle); - defaultStyle = URPreferencesUtil.loadStyle(defaultStyle, formatterPrefs); + if (load) + tempStyle.load(formatterPrefs); - return defaultStyle; + return tempStyle; } - public URStyle lowStyle() + public URStyle lowStyle(boolean load) { String name = "lowStyle"; - URStyle tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name, load); StyleConstants.setForeground(tempStyle, UIManager.getColor("Panel.background").darker()); - tempStyle = URPreferencesUtil.loadStyle(tempStyle, formatterPrefs); - - if(StyleConstants.getForeground(tempStyle).getRGB() == myForeground.getRGB()) + if (StyleConstants.getForeground(tempStyle).getRGB() == myForeground.getRGB()) if (URColour.useDarkColour(UIManager.getColor("Panel.background"))) { StyleConstants.setForeground(tempStyle, UIManager.getColor("Panel.background").darker()); @@ -134,25 +124,30 @@ public URStyle lowStyle() StyleConstants.setForeground(tempStyle, UIManager.getColor("Panel.background").brighter()); } + if (load) + tempStyle.load(formatterPrefs); + + return tempStyle; } - public URStyle mediumStyle() + public URStyle mediumStyle(boolean load) { String name = "mediumStyle"; - URStyle tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name, load); - tempStyle.load(formatterPrefs); + if (load) + tempStyle.load(formatterPrefs); return tempStyle; } - public URStyle highStyle() + public URStyle highStyle(boolean load) { String name = "highStyle"; - URStyle tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name, load); StyleConstants.setBackground(tempStyle, UIManager.getColor("CheckBoxMenuItem.selectionBackground")); StyleConstants.setForeground(tempStyle, @@ -161,16 +156,17 @@ public URStyle highStyle() StyleConstants.setBold(tempStyle, true); StyleConstants.setItalic(tempStyle, true); - tempStyle.load(formatterPrefs); + if (load) + tempStyle.load(formatterPrefs); return tempStyle; } - public URStyle urlStyle() + public URStyle urlStyle(boolean load) { String name = "urlStyle"; - URStyle tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name, load); tempStyle.addAttribute("name", name); tempStyle.addAttribute("type", "url"); @@ -179,18 +175,19 @@ public URStyle urlStyle() StyleConstants.setBold(tempStyle, true); StyleConstants.setUnderline(tempStyle, true); - tempStyle.load(formatterPrefs); + if (load) + tempStyle.load(formatterPrefs); return tempStyle; } // TODO: urlStyle and channelStyle don't load the correct styling in the fontPanel - public URStyle channelStyle() + public URStyle channelStyle(boolean load) { String name = "channelStyle"; - URStyle tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name, load); tempStyle.addAttribute("name", name); tempStyle.addAttribute("type", "channel"); @@ -199,17 +196,17 @@ public URStyle channelStyle() StyleConstants.setBold(tempStyle, true); StyleConstants.setUnderline(tempStyle, true); - // tempStyle.load(formatterPrefs); - tempStyle = URPreferencesUtil.loadStyle(tempStyle, formatterPrefs); + if (load) + tempStyle.load(formatterPrefs); return tempStyle; } - public URStyle myStyle() + public URStyle myStyle(boolean load) { String name = "myStyle"; - URStyle tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name, load); tempStyle.addAttribute("type", "myNick"); // StyleConstants.setForeground(tempStyle, Color.GREEN); @@ -219,21 +216,23 @@ public URStyle myStyle() StyleConstants.setBold(tempStyle, true); StyleConstants.setUnderline(tempStyle, true); - tempStyle.load(formatterPrefs); + if (load) + tempStyle.load(formatterPrefs); return tempStyle; } - public URStyle nickStyle() + public URStyle nickStyle(boolean load) { String name = "nickStyle"; - URStyle tempStyle = defaultStyle(name); + URStyle tempStyle = defaultStyle(name, load); tempStyle.addAttribute("type", "nick"); StyleConstants.setUnderline(tempStyle, true); - tempStyle.load(formatterPrefs); + if (load) + tempStyle.load(formatterPrefs); return tempStyle; } @@ -353,45 +352,45 @@ private void appendString(StyledDocument doc, String insertedString, SimpleAttri insertString(doc, insertedString, style, position); } - public URStyle getStyle(String styleName) + public URStyle getStyleBase(String styleName, boolean load) { switch (styleName) { case "mediumStyle": - return mediumStyle(); + return mediumStyle(load); case "highStyle": - return highStyle(); + return highStyle(load); case "nickStyle": - return nickStyle(); + return nickStyle(load); case "myStyle": - return myStyle(); + return myStyle(load); case "lowStyle": - return lowStyle(); + return lowStyle(load); case "urlStyle": - return urlStyle(); + return urlStyle(load); case "channelStyle": - return channelStyle(); + return channelStyle(load); default: - return defaultStyle(null); + return defaultStyle(null, true); } } - public Font getStyleAsFont(String styleName) - { - SimpleAttributeSet fontStyle = getStyle(styleName); + // public Font getStyleAsFont(String styleName) + // { + // SimpleAttributeSet fontStyle = getStyleBase(styleName); - int savedFontBoldItalic = 0; + // int savedFontBoldItalic = 0; - if (StyleConstants.isBold(fontStyle)) - savedFontBoldItalic = Font.BOLD; - if (StyleConstants.isItalic(fontStyle)) - savedFontBoldItalic |= Font.ITALIC; + // if (StyleConstants.isBold(fontStyle)) + // savedFontBoldItalic = Font.BOLD; + // if (StyleConstants.isItalic(fontStyle)) + // savedFontBoldItalic |= Font.ITALIC; - Font styleFont = new Font(StyleConstants.getFontFamily(fontStyle), savedFontBoldItalic, - StyleConstants.getFontSize(fontStyle)); + // Font styleFont = new Font(StyleConstants.getFontFamily(fontStyle), savedFontBoldItalic, + // StyleConstants.getFontSize(fontStyle)); - return styleFont; - } + // return styleFont; + // } public void updateStyles(StyledDocument doc, int startPosition) { @@ -401,7 +400,7 @@ public void updateStyles(StyledDocument doc, int startPosition) int styleStart = startPosition; int styleLength = Integer.parseInt(textStyle.getAttribute("styleLength").toString()); - SimpleAttributeSet matchingStyle = getStyle(styleName); + SimpleAttributeSet matchingStyle = getStyleBase(styleName, true); boolean isDateStyle = false; if (null != DriverGUI.gui && null != textStyle.getAttribute("date")) @@ -428,7 +427,7 @@ public void updateStyles(StyledDocument doc, int startPosition) if (!hasTime) doc.setCharacterAttributes(styleStart, styleLength, textStyle, true); - SimpleAttributeSet timeStyle = getStyle(styleName); + SimpleAttributeSet timeStyle = getStyleBase(styleName, true); timeStyle.addAttribute("date", lineDate); timeStyle.addAttribute("type", "time"); insertString(doc, newTimeString, timeStyle, styleStart); @@ -443,7 +442,7 @@ public void updateStyles(StyledDocument doc, int startPosition) styleStart = startPosition; styleLength = Integer.parseInt(textStyle.getAttribute("styleLength").toString()); - matchingStyle = getStyle(styleName); + matchingStyle = getStyleBase(styleName, true); matchingStyle.addAttribute("date", lineDate); isDateStyle = false; @@ -553,8 +552,8 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin throws BadLocationException { HashMap regexStrings = new HashMap<>(); - regexStrings.put(Constants.URL_REGEX, urlStyle()); - regexStrings.put(Constants.CHANNEL_REGEX, channelStyle()); + regexStrings.put(Constants.URL_REGEX, urlStyle(true)); + regexStrings.put(Constants.CHANNEL_REGEX, channelStyle(true)); // final String line = getLatestLine(doc); final int relativePosition = getLinePosition(doc, getLatestLine(doc)); @@ -571,7 +570,7 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin // do stuff for each match while (matcher.find()) { - URStyle linkStyle = getStyle(entry.getValue().getAttribute("name").toString()); + URStyle linkStyle = getStyleBase(entry.getValue().getAttribute("name").toString(), true); String clickableLine = matcher.group(1); linkStyle.addAttribute("clickableText", new ClickableText(clickableLine, linkStyle, fromUser)); @@ -629,22 +628,22 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse if (fromUser != null && null != myNick && myNick.equals(fromUser.toString())) { - nickStyle = myStyle(); + nickStyle = myStyle(true); } else { if (null != myNick && line.indexOf(myNick) > -1) - nickStyle = highStyle(); + nickStyle = highStyle(true); else - nickStyle = nickStyle(); + nickStyle = nickStyle(true); } if (fromUser == null && fromString.equals(Constants.EVENT_USER)) { - nickStyle = lowStyle(); - lineStyle = lowStyle(); + nickStyle = lowStyle(true); + lineStyle = lowStyle(true); } else { - lineStyle = defaultStyle(null); + lineStyle = defaultStyle(null, true); } timeStyle = lineStyle; diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index ba4dd1f..314bb14 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -62,7 +62,8 @@ public class UserGUI extends JPanel implements Runnable, UserGUIBase private static final JPanel interfacePanel = new JPanel(); private static final JScrollPane interfaceScroller = new JScrollPane(interfacePanel); - private static final JComboBox lafOptions = new JComboBox(UIManager.getInstalledLookAndFeels()); + private static final JComboBox lafOptions = + new JComboBox(UIManager.getInstalledLookAndFeels()); private static final JCheckBox showEventTicker = new JCheckBox("Show Event Ticker"); private static final JCheckBox showUsersList = new JCheckBox("Show Users List"); @@ -281,7 +282,7 @@ public IRCServerBase getCreatedServer(String serverName) public void setProfileName(String newProfileName) { // save the current profile settings, if it exists - if(profilePicker.profileExists(profileName)) + if (profilePicker.profileExists(profileName)) { setClientSettings(); } @@ -536,14 +537,14 @@ private static void addToPanel(JPanel targetPanel, Component newComponent, Strin final int LEFT_ALIGNED = 0; final int LEFT_SPACING = 6; - if(null != label && !label.isBlank()) + if (null != label && !label.isBlank()) { addToPanel(targetPanel, new JLabel(label + ":"), null, targetSize); // There is a label, so we want the added component to be aligned with the label topSpacing = 0; } - if(targetPanel.getLayout().getClass() != SpringLayout.class) + if (targetPanel.getLayout().getClass() != SpringLayout.class) { targetPanel.setLayout(new SpringLayout()); } @@ -551,7 +552,8 @@ private static void addToPanel(JPanel targetPanel, Component newComponent, Strin SpringLayout layout = (SpringLayout) targetPanel.getLayout(); Component[] components = targetPanel.getComponents(); - if (components.length > 0) { + if (components.length > 0) + { Component previousComponent = components[components.length - 1]; // Add newComponent to the targetPanel @@ -561,9 +563,10 @@ private static void addToPanel(JPanel targetPanel, Component newComponent, Strin layout.putConstraint(SpringLayout.NORTH, newComponent, topSpacing, SpringLayout.SOUTH, previousComponent); layout.putConstraint(SpringLayout.WEST, newComponent, LEFT_ALIGNED, SpringLayout.WEST, previousComponent); - if(null != targetSize && newComponent instanceof JTextField) + if (null != targetSize && newComponent instanceof JTextField) ((JTextField) newComponent).setColumns(12); - } else { + } else + { // If it's the first component, align it against the targetPanel targetPanel.add(newComponent); @@ -571,7 +574,7 @@ private static void addToPanel(JPanel targetPanel, Component newComponent, Strin layout.putConstraint(SpringLayout.NORTH, newComponent, topSpacing * 2, SpringLayout.NORTH, targetPanel); layout.putConstraint(SpringLayout.WEST, newComponent, LEFT_SPACING * 2, SpringLayout.WEST, targetPanel); - if(null != targetSize && newComponent instanceof JTextField) + if (null != targetSize && newComponent instanceof JTextField) ((JTextField) newComponent).setColumns(12); } } @@ -772,7 +775,8 @@ private void setupConnectionLayout() connectionLayout.putConstraint(SpringLayout.EAST, proxyHostNameTextField, RIGHT_ALIGNED, SpringLayout.EAST, servernameTextField); - connectionLayout.putConstraint(SpringLayout.NORTH, proxyPortLabel, TOP_ALIGNED, SpringLayout.NORTH, proxyHostLabel); + connectionLayout.putConstraint(SpringLayout.NORTH, proxyPortLabel, TOP_ALIGNED, SpringLayout.NORTH, + proxyHostLabel); connectionLayout.putConstraint(SpringLayout.WEST, proxyPortLabel, LEFT_ALIGNED, SpringLayout.EAST, proxyHostNameTextField); @@ -831,9 +835,12 @@ private void setupAppearancePanel() addToPanel(appearancePanel, lafOptions, "Theme", Size.MEDIUM); // Set a custom renderer to display the look and feel names - lafOptions.setRenderer(new DefaultListCellRenderer() { + lafOptions.setRenderer(new DefaultListCellRenderer() + { @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, + boolean cellHasFocus) + { LookAndFeelInfo info = (LookAndFeelInfo) value; return super.getListCellRendererComponent(list, info.getName(), index, isSelected, cellHasFocus); } @@ -849,19 +856,23 @@ public Component getListCellRendererComponent(JList list, Object value, int i previewTextScroll.setPreferredSize(new Dimension(700, 150)); previewTextArea.setEditable(false); - timeStampField.addKeyListener(new KeyListener() { + timeStampField.addKeyListener(new KeyListener() + { @Override - public void keyTyped(KeyEvent e) { + public void keyTyped(KeyEvent e) + { // Not used } @Override - public void keyPressed(KeyEvent e) { + public void keyPressed(KeyEvent e) + { // Not used } @Override - public void keyReleased(KeyEvent e) { + public void keyReleased(KeyEvent e) + { updatePreviewTextArea(); } }); @@ -888,18 +899,18 @@ public void updatePreviewTextArea() // try // { - // // Clear all text - // previewDoc.remove(0, previewDoc.getLength()); + // // Clear all text + // previewDoc.remove(0, previewDoc.getLength()); // } catch (BadLocationException e) // { - // // TODO Auto-generated catch block - // e.printStackTrace(); + // // TODO Auto-generated catch block + // e.printStackTrace(); // } // previewTextArea.setFont(clientFontPanel.getFont()); - previewLineFormatter = new LineFormatter(clientFontPanel.getStyle() ,null, getProfilePath(), null); + previewLineFormatter = new LineFormatter(clientFontPanel.getStyle(), null, getProfilePath()); - if(previewDoc.getLength() <= 0) + if (previewDoc.getLength() <= 0) { previewTextArea.setCaretPosition(previewTextArea.getDocument().getLength()); previewTextArea.addMouseListener(new PreviewClickListener()); @@ -907,12 +918,18 @@ public void updatePreviewTextArea() IRCUser tempUser = new IRCUser(null, "matty_r"); IRCUser tempUser2 = new IRCUser(null, System.getProperty("user.name")); previewLineFormatter.setNick(System.getProperty("user.name")); - previewLineFormatter.formattedDocument(previewDoc, new Date(), null, Constants.EVENT_USER, "urChat has loaded - this is an Event"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "Normal line. Hello, world!"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", "This is what it looks like when your nick is mentioned, "+System.getProperty("user.name")+"!"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), "Go to https://github.com/matty-r/urChat"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), "Join #urchatclient on irc.libera.chat or #anotherroom"); - } else { + previewLineFormatter.formattedDocument(previewDoc, new Date(), null, Constants.EVENT_USER, + "urChat has loaded - this is an Event"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", + "Normal line. Hello, world!"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", + "This is what it looks like when your nick is mentioned, " + System.getProperty("user.name") + "!"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), + "Go to https://github.com/matty-r/urChat"); + previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), + "Join #urchatclient on irc.libera.chat or #anotherroom"); + } else + { previewLineFormatter.updateStyles(previewDoc, 0); } } @@ -929,10 +946,11 @@ public void mouseClicked(MouseEvent mouseEvent) if (SwingUtilities.isRightMouseButton(mouseEvent) && wordAttributeSet.getAttribute("name") != null) { String styleName = styleLabel.getText(); - FontDialog styleFontDialog = new FontDialog(styleName, guiStyle, getProfilePath()); + FontDialog styleFontDialog = new FontDialog(styleName, + previewLineFormatter.getStyleBase(styleName, false), getProfilePath()); styleFontDialog.addSaveListener(arg0 -> { - List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); + // List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); // TODO: Need to save attributes and updateStyles after.. // Currently runs the save after updateStyles previewLineFormatter.updateStyles(doc, 0); @@ -940,17 +958,17 @@ public void mouseClicked(MouseEvent mouseEvent) // styleFontDialog.addResetListener(new ActionListener() { - // @Override - // public void actionPerformed(ActionEvent arg0) { - // try { - // getProfilePath().node(styleName).removeNode(); - // } catch (BackingStoreException e) { - // // TODO Auto-generated catch block - // e.printStackTrace(); - // } + // @Override + // public void actionPerformed(ActionEvent arg0) { + // try { + // getProfilePath().node(styleName).removeNode(); + // } catch (BackingStoreException e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } - // previewLineFormatter.updateStyles(doc, 0); - // } + // previewLineFormatter.updateStyles(doc, 0); + // } // }); @@ -972,7 +990,7 @@ public void mouseMoved(MouseEvent e) AttributeSet wordAttributeSet = wordElement.getAttributes(); ClickableText isClickableText = (ClickableText) wordAttributeSet.getAttribute("clickableText"); - if(wordAttributeSet.getAttribute("name") != null) + if (wordAttributeSet.getAttribute("name") != null) styleLabel.setText(wordAttributeSet.getAttribute("name").toString()); else styleLabel.setText("Mouse over text to view style, right-click to edit."); @@ -1045,11 +1063,15 @@ private void setupInterfaceLayout() // Components are aligned off the top label - interfaceLayout.putConstraint(SpringLayout.WEST, showEventTicker, LEFT_SPACING * 2, SpringLayout.WEST, interfacePanel); - interfaceLayout.putConstraint(SpringLayout.NORTH, showEventTicker, TOP_SPACING * 2, SpringLayout.NORTH, interfacePanel); + interfaceLayout.putConstraint(SpringLayout.WEST, showEventTicker, LEFT_SPACING * 2, SpringLayout.WEST, + interfacePanel); + interfaceLayout.putConstraint(SpringLayout.NORTH, showEventTicker, TOP_SPACING * 2, SpringLayout.NORTH, + interfacePanel); - interfaceLayout.putConstraint(SpringLayout.NORTH, showUsersList, TOP_SPACING, SpringLayout.SOUTH, showEventTicker); - interfaceLayout.putConstraint(SpringLayout.WEST, showUsersList, LEFT_ALIGNED, SpringLayout.WEST, showEventTicker); + interfaceLayout.putConstraint(SpringLayout.NORTH, showUsersList, TOP_SPACING, SpringLayout.SOUTH, + showEventTicker); + interfaceLayout.putConstraint(SpringLayout.WEST, showUsersList, LEFT_ALIGNED, SpringLayout.WEST, + showEventTicker); interfaceLayout.putConstraint(SpringLayout.NORTH, enableClickableLinks, TOP_SPACING, SpringLayout.SOUTH, showUsersList); @@ -1084,7 +1106,8 @@ private void setupInterfaceLayout() interfaceLayout.putConstraint(SpringLayout.NORTH, limitServerLines, TOP_SPACING, SpringLayout.SOUTH, logClientText); - interfaceLayout.putConstraint(SpringLayout.WEST, limitServerLines, LEFT_ALIGNED, SpringLayout.WEST, logClientText); + interfaceLayout.putConstraint(SpringLayout.WEST, limitServerLines, LEFT_ALIGNED, SpringLayout.WEST, + logClientText); interfaceLayout.putConstraint(SpringLayout.NORTH, limitServerLinesCount, TOP_ALIGNED, SpringLayout.NORTH, limitServerLines); @@ -1606,9 +1629,8 @@ public void getClientSettings(boolean loadWindowSettings) clientFontPanel.loadStyle(); - timeStampField.setText( - getProfilePath().get(Constants.KEY_TIME_STAMP_FORMAT, Constants.DEFAULT_TIME_STAMP_FORMAT) - ); + timeStampField + .setText(getProfilePath().get(Constants.KEY_TIME_STAMP_FORMAT, Constants.DEFAULT_TIME_STAMP_FORMAT)); updatePreviewTextArea(); @@ -1680,10 +1702,10 @@ public void cleanUpSettings() for (String profileNode : getProfilePath().childrenNames()) { - if (getProfilePath().node(profileNode).keys().length == 0) - { - getProfilePath().node(profileNode).removeNode(); - } + if (getProfilePath().node(profileNode).keys().length == 0) + { + getProfilePath().node(profileNode).removeNode(); + } } } catch (BackingStoreException e) { @@ -1950,8 +1972,10 @@ public URStyle getStyle() private LookAndFeelInfo getLAF(String lafClassName) { - for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { - if (lafClassName.equals(info.getClassName())) { + for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) + { + if (lafClassName.equals(info.getClassName())) + { return info; } } @@ -1973,22 +1997,27 @@ private void setNewLAF(String newLAFname) try { - try{ - for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { + try + { + for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) + { // System.out.println(info.getName()); - if (newLAFname.equals(info.getClassName())) { + if (newLAFname.equals(info.getClassName())) + { UIManager.setLookAndFeel(info.getClassName()); flatLafAvailable = true; } } - } catch(Exception e) { + } catch (Exception e) + { throw e; } } catch (Exception e) { Constants.LOGGER.log(Level.WARNING, "Failed to set Pluggable LAF! " + e.getLocalizedMessage()); - } finally { - if(!flatLafAvailable) + } finally + { + if (!flatLafAvailable) { try { @@ -2006,10 +2035,10 @@ private void setNewLAF(String newLAFname) guiStyle.setFont(clientFontPanel.getFont()); // reset the defaults on the guiStyle if they were already at the default - if(previousDefaultForeground == guiStyle.getForeground()) + if (previousDefaultForeground == guiStyle.getForeground()) guiStyle.setForeground(UIManager.getColor("Label.foreground")); - if(previousDefaultBackground == guiStyle.getBackground()) + if (previousDefaultBackground == guiStyle.getBackground()) guiStyle.setBackground(UIManager.getColor("Panel.background")); SwingUtilities.updateComponentTreeUI(DriverGUI.frame); diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index fbdf28e..7aaeede 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -32,8 +32,8 @@ public ColourPanel(String styleName, URStyle defaultStyle, Preferences settingsP saveButton = new JButton("Apply & Save"); previewLabel = new JLabel("Preview Text"); this.settingsPath = settingsPath; - this.defaultStyle = defaultStyle; - targetStyle = new URStyle(styleName, defaultStyle.getFont()); + this.defaultStyle = defaultStyle.clone(); + targetStyle = defaultStyle.clone(); loadStyle(); bottomPanel = createBottomPanel(); @@ -86,6 +86,8 @@ public JPanel createBottomPanel() }); resetButton.addActionListener(e -> { + // URPreferencesUtil.deleteStyleColours(targetStyle, settingsPath); + // defaultStyle.load(settingsPath); previewLabel.setFont(defaultStyle.getFont()); setPreviewColour(defaultStyle.getForeground(), true); setPreviewColour(defaultStyle.getBackground(), false); @@ -103,7 +105,10 @@ public JPanel createBottomPanel() saveButton.addActionListener(e -> { // Save the style first - URPreferencesUtil.saveStyle(targetStyle, settingsPath); + if(targetStyle.equals(defaultStyle)) + URPreferencesUtil.deleteStyleColours(targetStyle, settingsPath); + else + URPreferencesUtil.saveStyle(targetStyle, settingsPath); // now fire the rest of the save listeners fireSaveListeners(); From 61d0d7e317d57bb03b94d674cc7cdb032ee4ff72 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 10 Dec 2023 05:46:22 +1000 Subject: [PATCH 67/78] Fixes up the cloning of URStyle. LineFormatter no longer 'loads' the style everytime - this should be vastly more performant. --- .../backend/utils/URPreferencesUtil.java | 3 + src/urChatBasic/backend/utils/URStyle.java | 2 +- src/urChatBasic/base/IRCRoomBase.java | 3 +- src/urChatBasic/frontend/LineFormatter.java | 119 +++++++++++------- src/urChatBasic/frontend/UserGUI.java | 7 +- .../frontend/components/ColourPanel.java | 5 + .../frontend/components/FontPanel.java | 9 ++ 7 files changed, 96 insertions(+), 52 deletions(-) diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index 5d2ba77..bf6ec6b 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -68,6 +68,9 @@ public static URStyle loadStyle(final URStyle targetStyle, Preferences baseSetti // targetStyle = targetStyle.clone(); // Default to the profile path node Preferences stylePrefPath = baseSettingsPath; + if(targetStyle.getAttribute("name") == null) + targetStyle.addAttribute("name", ""); + try { if(baseSettingsPath.nodeExists(targetStyle.getAttribute("name").toString())) diff --git a/src/urChatBasic/backend/utils/URStyle.java b/src/urChatBasic/backend/utils/URStyle.java index 5cca6ed..4e337d0 100644 --- a/src/urChatBasic/backend/utils/URStyle.java +++ b/src/urChatBasic/backend/utils/URStyle.java @@ -112,6 +112,6 @@ public boolean equals (URStyle otherStyle) @Override public URStyle clone () { - return new URStyle(getName(), getFont(), getForeground(), getBackground()); + return (URStyle) super.clone(); } } diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index d64a08b..7db1758 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -521,8 +521,7 @@ public void run() { lineFormatter.formattedDocument(doc, new Date(), fromIRCUser, fromUser, line); - if (lineFormatter.myStyle.getAttribute("name") == lineFormatter.highStyle(true) - .getAttribute("name")) + if (server.getNick() != null && line.indexOf(server.getNick()) > -1) { callForAttention(); } diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 2f82411..dd8e1e5 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -39,10 +39,17 @@ public class LineFormatter private Color myBackground; private IRCServerBase myServer; private Preferences formatterPrefs; - public URStyle timeStyle; - public URStyle lineStyle; - public URStyle nickStyle; + private URStyle urlStyle; + private URStyle channelStyle; + private URStyle timeStyle; + private URStyle lineStyle; + private URStyle nickStyle; + private URStyle highStyle; + private URStyle mediumStyle; + private URStyle lowStyle; public URStyle myStyle; + private Map formatterStyles = new HashMap<>(); + public LineFormatter(URStyle baseStyle, final IRCServerBase server, Preferences formatterPrefs) { @@ -67,10 +74,26 @@ public LineFormatter(URStyle baseStyle, final IRCServerBase server, Preferences myForeground = targetStyle.getForeground(); myBackground = targetStyle.getBackground(); + // TODO: split this mess out to a method timeStyle = defaultStyle(null, true); lineStyle = defaultStyle(null, true); - nickStyle = nickStyle(false); - myStyle = myStyle(false); + nickStyle = nickStyle(true); + myStyle = myStyle(true); + channelStyle = channelStyle(true); + urlStyle = urlStyle(true); + highStyle = highStyle(true); + mediumStyle = mediumStyle(true); + lowStyle = lowStyle(true); + + formatterStyles.put(timeStyle.getName(), timeStyle); + formatterStyles.put(lineStyle.getName(), lineStyle); + formatterStyles.put(nickStyle.getName(), nickStyle); + formatterStyles.put(myStyle.getName(), myStyle); + formatterStyles.put(channelStyle.getName(), channelStyle); + formatterStyles.put(urlStyle.getName(), urlStyle); + formatterStyles.put(highStyle.getName(), highStyle); + formatterStyles.put(mediumStyle.getName(), mediumStyle); + formatterStyles.put(lowStyle.getName(), lowStyle); } public void setFont(StyledDocument doc, Font newFont) @@ -375,24 +398,24 @@ public URStyle getStyleBase(String styleName, boolean load) } } - // public Font getStyleAsFont(String styleName) - // { - // SimpleAttributeSet fontStyle = getStyleBase(styleName); - - // int savedFontBoldItalic = 0; - - // if (StyleConstants.isBold(fontStyle)) - // savedFontBoldItalic = Font.BOLD; - // if (StyleConstants.isItalic(fontStyle)) - // savedFontBoldItalic |= Font.ITALIC; + /** + * Reloads all the styles, then updates the doc + * @param doc + * @param startPosition + */ + public void updateStyles(StyledDocument doc, int startPosition) + { + targetStyle.load(formatterPrefs); - // Font styleFont = new Font(StyleConstants.getFontFamily(fontStyle), savedFontBoldItalic, - // StyleConstants.getFontSize(fontStyle)); + for (URStyle formatterStyle : formatterStyles.values()) { + formatterStyle = getStyleBase(formatterStyle.getName(), true); + } - // return styleFont; - // } + System.out.println("Updating styles."); + updateDocStyles(doc, startPosition); + } - public void updateStyles(StyledDocument doc, int startPosition) + private void updateDocStyles(StyledDocument doc, int startPosition) { SimpleAttributeSet textStyle = new SimpleAttributeSet(doc.getCharacterElement(startPosition).getAttributes()); @@ -552,8 +575,8 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin throws BadLocationException { HashMap regexStrings = new HashMap<>(); - regexStrings.put(Constants.URL_REGEX, urlStyle(true)); - regexStrings.put(Constants.CHANNEL_REGEX, channelStyle(true)); + regexStrings.put(Constants.URL_REGEX, urlStyle); + regexStrings.put(Constants.CHANNEL_REGEX, channelStyle); // final String line = getLatestLine(doc); final int relativePosition = getLinePosition(doc, getLatestLine(doc)); @@ -570,7 +593,7 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin // do stuff for each match while (matcher.find()) { - URStyle linkStyle = getStyleBase(entry.getValue().getAttribute("name").toString(), true); + URStyle linkStyle = entry.getValue().clone(); String clickableLine = matcher.group(1); linkStyle.addAttribute("clickableText", new ClickableText(clickableLine, linkStyle, fromUser)); @@ -625,29 +648,31 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse { // build the timeLine string String timeLine = UserGUI.getTimeLineString(lineDate); + final URStyle nickPositionStyle; + final URStyle linePositionStyle; if (fromUser != null && null != myNick && myNick.equals(fromUser.toString())) { - nickStyle = myStyle(true); + // This message is from me + nickPositionStyle = myStyle; + linePositionStyle = lineStyle; + } else if (fromUser == null && fromString.equals(Constants.EVENT_USER)) + { + // This is an event message + nickPositionStyle = lowStyle; + linePositionStyle = lowStyle; } else { - if (null != myNick && line.indexOf(myNick) > -1) - nickStyle = highStyle(true); + // This message is from someone else + // Does this message have my nick in it? + if (myNick != null && line.indexOf(myNick) > -1) + nickPositionStyle = highStyle; else - nickStyle = nickStyle(true); - } + nickPositionStyle = nickStyle; - if (fromUser == null && fromString.equals(Constants.EVENT_USER)) - { - nickStyle = lowStyle(true); - lineStyle = lowStyle(true); - } else - { - lineStyle = defaultStyle(null, true); + linePositionStyle = lineStyle; } - timeStyle = lineStyle; - try { @@ -662,38 +687,38 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse timeStyle.addAttribute("type", "time"); appendString(doc, timeLine + " ", timeStyle); timeStyle.removeAttribute("type"); - lineStyle.removeAttribute("date"); + linePositionStyle.removeAttribute("date"); } else { - lineStyle.addAttribute("date", lineDate); + linePositionStyle.addAttribute("date", lineDate); } - appendString(doc, "<", lineStyle); - lineStyle.removeAttribute("date"); + appendString(doc, "<", linePositionStyle); + linePositionStyle.removeAttribute("date"); if (fromUser != null) { - URStyle clickableNameStyle = nickStyle; + URStyle clickableNameStyle = nickPositionStyle; clickableNameStyle.addAttribute("type", "IRCUser"); clickableNameStyle.addAttribute("clickableText", - new ClickableText(fromUser.toString(), nickStyle, fromUser)); + new ClickableText(fromUser.toString(), nickPositionStyle, fromUser)); // doc.insertString(doc.getLength(), fromUser.toString(), clickableNameStyle); appendString(doc, fromUser.toString(), clickableNameStyle); } else { - appendString(doc, fromString, nickStyle); + appendString(doc, fromString, nickPositionStyle); } - appendString(doc, ">", lineStyle); + appendString(doc, ">", linePositionStyle); // print the remaining text // appendString(doc, " "+line, lineStyle); // parse the outputted line for clickable text - parseClickableText(doc, fromUser, " " + line, lineStyle); + parseClickableText(doc, fromUser, " " + line, linePositionStyle); - appendString(doc, System.getProperty("line.separator"), lineStyle); + appendString(doc, System.getProperty("line.separator"), linePositionStyle); } catch (BadLocationException e) { Constants.LOGGER.log(Level.SEVERE, e.getLocalizedMessage()); diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 314bb14..a022eea 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -850,7 +850,9 @@ public Component getListCellRendererComponent(JList list, Object value, int i clientFontPanel = new FontPanel("", getStyle(), getProfilePath()); clientFontPanel.setPreferredSize(new Dimension(700, 64)); - clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); + clientFontPanel.addActionListener(clientFontPanel.getSaveButton(), new SaveFontListener()); + + // clientFontPanel.getSaveButton().addActionListener(new SaveFontListener()); clientFontPanel.getResetButton().addActionListener(new ResetFontListener()); previewTextScroll.setPreferredSize(new Dimension(700, 150)); @@ -1893,7 +1895,8 @@ public void actionPerformed(ActionEvent arg0) favouriteItem.favFontDialog.getFontPanel().loadStyle(); } - previewLineFormatter.setFont(previewTextArea.getStyledDocument(), clientFontPanel.getFont()); + // previewLineFormatter.setFont(previewTextArea.getStyledDocument(), clientFontPanel.getFont()); + previewLineFormatter.updateStyles(previewTextArea.getStyledDocument(), 0); } } diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index 7aaeede..df30b40 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -168,6 +168,11 @@ public void loadStyle() setPreviewColour(targetStyle.getBackground(), false); } + public URStyle getStyle() + { + return targetStyle; + } + public void stateChanged(ChangeEvent e) { selectedColor = tcc.getColor(); diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 8b952d2..77c2138 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -71,6 +71,10 @@ public void actionPerformed(ActionEvent arg0) // URPreferencesUtil.saveStyle(targetStyle, settingsPath); System.out.println("Font Panel says: Save Colour pressed"); }); + + for (ActionListener actionListener : actionListeners) { + colourDialog.getColourPanel().addSaveListener(actionListener); + } } colourDialog.setVisible(true); @@ -205,7 +209,12 @@ public void setFont(Font newFont, Boolean saveToSettings) targetStyle.setFont(newFont); if(saveToSettings) + { + URStyle colourPanelStyle = colourDialog.getColourPanel().getStyle(); + targetStyle.setForeground(colourPanelStyle.getForeground()); + targetStyle.setBackground(colourPanelStyle.getBackground()); targetStyle.save(settingsPath); + } revalidate(); repaint(); From cab3e4807c46aff0b34415c9d7fd53461f51f968 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 10 Dec 2023 07:42:37 +1000 Subject: [PATCH 68/78] Improving font support (i.e. adding support for underline) --- .../backend/utils/URPreferencesUtil.java | 54 +++++++-------- src/urChatBasic/backend/utils/URStyle.java | 65 ++++++++++++++----- src/urChatBasic/base/Constants.java | 18 ++++- src/urChatBasic/base/IRCRoomBase.java | 3 +- src/urChatBasic/frontend/LineFormatter.java | 46 +++++++------ src/urChatBasic/frontend/UserGUI.java | 2 +- .../frontend/components/FontPanel.java | 38 +++++++---- 7 files changed, 149 insertions(+), 77 deletions(-) diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index bf6ec6b..d97216e 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -2,12 +2,13 @@ import java.awt.Color; import java.awt.Font; +import java.awt.font.TextAttribute; import java.util.HashMap; +import java.util.Hashtable; import java.util.Map; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.swing.UIManager; -import javax.swing.text.StyleConstants; import urChatBasic.base.Constants; import urChatBasic.frontend.DriverGUI; import urChatBasic.frontend.utils.URColour; @@ -16,22 +17,35 @@ public class URPreferencesUtil { /** * Uses the defaultFont for the returned font if there is no font saved. + * TODO: This should really go through an enum of font keys and apply them all instead? * @param defaultFont * @param settingsPath * @return */ public static Font loadStyleFont(Font defaultFont, Preferences settingsPath) { + // Font savedFont = defaultFont; + // int savedFontBoldItalic = 0; + + // if (settingsPath.getBoolean(Constants.KEY_FONT_BOLD, defaultFont.isBold())) + // savedFontBoldItalic = Font.BOLD; + // if (settingsPath.getBoolean(Constants.KEY_FONT_ITALIC, defaultFont.isItalic())) + // savedFontBoldItalic |= Font.ITALIC; + + // savedFont = new Font(settingsPath.get(Constants.KEY_FONT_FAMILY, defaultFont.getFamily()), + // savedFontBoldItalic, settingsPath.getInt(Constants.KEY_FONT_SIZE, defaultFont.getSize())); + + // return savedFont; Font savedFont = defaultFont; - int savedFontBoldItalic = 0; - if (settingsPath.getBoolean(Constants.KEY_FONT_BOLD, defaultFont.isBold())) - savedFontBoldItalic = Font.BOLD; - if (settingsPath.getBoolean(Constants.KEY_FONT_ITALIC, defaultFont.isItalic())) - savedFontBoldItalic |= Font.ITALIC; + Map fontMap = new Hashtable(); - savedFont = new Font(settingsPath.get(Constants.KEY_FONT_FAMILY, defaultFont.getFamily()), - savedFontBoldItalic, settingsPath.getInt(Constants.KEY_FONT_SIZE, defaultFont.getSize())); + fontMap.put(TextAttribute.WEIGHT, settingsPath.getBoolean(Constants.KEY_FONT_BOLD, defaultFont.isBold()) ? TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR); + fontMap.put(TextAttribute.POSTURE, settingsPath.getBoolean(Constants.KEY_FONT_ITALIC, defaultFont.isItalic()) ? TextAttribute.POSTURE_OBLIQUE : TextAttribute.POSTURE_REGULAR); + fontMap.put(TextAttribute.UNDERLINE, settingsPath.getBoolean(Constants.KEY_FONT_UNDERLINE, URStyle.isUnderline(defaultFont)) ? TextAttribute.UNDERLINE_ON : -1); + + savedFont = new Font(settingsPath.get(Constants.KEY_FONT_FAMILY, defaultFont.getFamily()), Font.PLAIN, settingsPath.getInt(Constants.KEY_FONT_SIZE, defaultFont.getSize())) + .deriveFont(fontMap); return savedFont; } @@ -85,31 +99,15 @@ else if (DriverGUI.gui != null) e.printStackTrace(); } - System.out.println("Load Style Path: " + stylePrefPath.toString()); Font loadedFont = loadStyleFont(targetStyle.getFont(), stylePrefPath); // LineFormatter.getStyleAsFont(defaultStyle); Map loadedColours = loadStyleColours(targetStyle, stylePrefPath); // LineFormatter.getStyleColours(defaultStyle); - StyleConstants.setFontFamily(targetStyle, - loadedFont.getFamily()); - - StyleConstants.setFontSize(targetStyle, - loadedFont.getSize()); - - StyleConstants.setBold(targetStyle, - loadedFont.isBold()); - - StyleConstants.setItalic(targetStyle, - loadedFont.isItalic()); - - StyleConstants.setForeground(targetStyle, loadedColours.get(Constants.KEY_FONT_FOREGROUND)); - - StyleConstants.setBackground(targetStyle, loadedColours.get(Constants.KEY_FONT_BACKGROUND)); - - // System.out.println("Loaded: "+targetStyle.getAttribute("name") + ". Font: "+loadedFont.getFamily() + - // " Colours - fg: "+URColour.hexEncode(targetStyle.getForeground()) + " bg: " + URColour.hexEncode(targetStyle.getBackground())); + targetStyle.setFont(loadedFont); + targetStyle.setForeground(loadedColours.get(Constants.KEY_FONT_FOREGROUND)); + targetStyle.setBackground(loadedColours.get(Constants.KEY_FONT_BACKGROUND)); return targetStyle.clone(); } @@ -124,6 +122,7 @@ public static void deleteStyleFont(URStyle targetStyle, Preferences baseSettings settingsPath.remove(Constants.KEY_FONT_ITALIC); settingsPath.remove(Constants.KEY_FONT_FAMILY); settingsPath.remove(Constants.KEY_FONT_SIZE); + settingsPath.remove(Constants.KEY_FONT_UNDERLINE); } catch (Exception e) { // TODO Auto-generated catch block @@ -164,6 +163,7 @@ private static void saveStyleFont(Font newFont, Preferences settingsPath) // TODO: Don't safe if it's the default font settingsPath.putBoolean(Constants.KEY_FONT_BOLD, newFont.isBold()); settingsPath.putBoolean(Constants.KEY_FONT_ITALIC, newFont.isItalic()); + settingsPath.putBoolean(Constants.KEY_FONT_UNDERLINE, URStyle.isUnderline(newFont)); settingsPath.put(Constants.KEY_FONT_FAMILY, newFont.getFamily()); settingsPath.putInt(Constants.KEY_FONT_SIZE, newFont.getSize()); } diff --git a/src/urChatBasic/backend/utils/URStyle.java b/src/urChatBasic/backend/utils/URStyle.java index 4e337d0..4458083 100644 --- a/src/urChatBasic/backend/utils/URStyle.java +++ b/src/urChatBasic/backend/utils/URStyle.java @@ -2,26 +2,31 @@ import java.awt.Color; import java.awt.Font; +import java.awt.font.TextAttribute; +import java.util.Hashtable; +import java.util.Map; import java.util.prefs.Preferences; import javax.swing.UIManager; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; -public class URStyle extends SimpleAttributeSet { +public class URStyle extends SimpleAttributeSet +{ // /** - // * Create a URStyle with defaults - // */ + // * Create a URStyle with defaults + // */ // public URStyle (String name) // { - // this(name, Constants.DEFAULT_FONT_GENERAL); + // this(name, Constants.DEFAULT_FONT_GENERAL); // } /** * Create a URStyle based on defaultFont + * * @param defaultFont */ - public URStyle (String name, Font defaultFont) + public URStyle(String name, Font defaultFont) { super(); this.addAttribute("name", name); @@ -32,9 +37,10 @@ public URStyle (String name, Font defaultFont) /** * Create a URStyle based on defaultFont + * * @param defaultFont */ - public URStyle (String name, Font defaultFont, Color defaultForeground, Color defaultBackground) + public URStyle(String name, Font defaultFont, Color defaultForeground, Color defaultBackground) { super(); this.addAttribute("name", name); @@ -50,17 +56,27 @@ public String getName() public Font getFont() { - int savedFontBoldItalic = 0; + // int savedFontBoldItalic = 0; - if (StyleConstants.isBold(this)) - savedFontBoldItalic = Font.BOLD; - if (StyleConstants.isItalic(this)) - savedFontBoldItalic |= Font.ITALIC; + // if (StyleConstants.isBold(this)) + // savedFontBoldItalic = Font.BOLD; + // if (StyleConstants.isItalic(this)) + // savedFontBoldItalic |= Font.ITALIC; - Font styleFont = new Font(StyleConstants.getFontFamily(this), savedFontBoldItalic, - StyleConstants.getFontSize(this)); + Map fontMap = new Hashtable(); + + fontMap.put(TextAttribute.WEIGHT, StyleConstants.isBold(this) ? TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR); + fontMap.put(TextAttribute.POSTURE, StyleConstants.isItalic(this) ? TextAttribute.POSTURE_OBLIQUE : TextAttribute.POSTURE_REGULAR); + fontMap.put(TextAttribute.UNDERLINE, StyleConstants.isUnderline(this) ? TextAttribute.UNDERLINE_ON : -1); + + Font styleFont = new Font(StyleConstants.getFontFamily(this), Font.PLAIN, StyleConstants.getFontSize(this)) + .deriveFont(fontMap); return styleFont; + // Font styleFont = new Font(StyleConstants.getFontFamily(this), savedFontBoldItalic, + // StyleConstants.getFontSize(this)); + + // return styleFont; } public void setFont(Font newFont) @@ -69,6 +85,7 @@ public void setFont(Font newFont) StyleConstants.setBold(this, newFont.isBold()); StyleConstants.setItalic(this, newFont.isItalic()); StyleConstants.setFontSize(this, newFont.getSize()); + StyleConstants.setUnderline(this, isUnderline(newFont)); } public Color getForeground() @@ -76,6 +93,21 @@ public Color getForeground() return StyleConstants.getForeground(this); } + + public boolean isUnderline() + { + return StyleConstants.isUnderline(this); + } + + // https://docs.oracle.com/javase/6/docs/api/java/awt/font/TextAttribute.html#UNDERLINE + public static boolean isUnderline(Font targetFont) + { + if (targetFont != null && targetFont.getAttributes().get(TextAttribute.UNDERLINE) != null) + return (int) targetFont.getAttributes().get(TextAttribute.UNDERLINE) == TextAttribute.UNDERLINE_ON; + + return false; + } + public Color getBackground() { return StyleConstants.getBackground(this); @@ -104,13 +136,14 @@ public void save(Preferences prefPath) URPreferencesUtil.saveStyle(this, prefPath); } - public boolean equals (URStyle otherStyle) + public boolean equals(URStyle otherStyle) { - return getFont().equals(otherStyle.getFont()) && getForeground().equals(otherStyle.getForeground()) && getBackground().equals(otherStyle.getBackground()); + return getFont().equals(otherStyle.getFont()) && getForeground().equals(otherStyle.getForeground()) + && getBackground().equals(otherStyle.getBackground()); } @Override - public URStyle clone () + public URStyle clone() { return (URStyle) super.clone(); } diff --git a/src/urChatBasic/base/Constants.java b/src/urChatBasic/base/Constants.java index 5de1414..6328ba2 100644 --- a/src/urChatBasic/base/Constants.java +++ b/src/urChatBasic/base/Constants.java @@ -10,6 +10,7 @@ import java.util.prefs.Preferences; import javax.swing.JLabel; import javax.swing.UIManager; +import javax.swing.text.StyleConstants; import urChatBasic.backend.Connection; import urChatBasic.base.capabilities.CapabilityTypes; import urChatBasic.frontend.DriverGUI; @@ -19,7 +20,7 @@ /** * Used to store constants that are the same and do not change often. These are things used commonly * across the [front,back]end - * + * */ public class Constants { @@ -72,6 +73,7 @@ public class Constants public static final String KEY_FONT_FAMILY = "font family"; public static final String KEY_FONT_BOLD = "font bold"; public static final String KEY_FONT_ITALIC = "font italic"; + public static final String KEY_FONT_UNDERLINE = "font underline"; public static final String KEY_FONT_SIZE = "font size"; public static final String KEY_FONT_FOREGROUND = "font foreground"; public static final String KEY_FONT_BACKGROUND = "font background"; @@ -142,6 +144,20 @@ public enum Size { NONE } + // TODO: put all the font prefs in an enum? + public enum FONT_PREFS { + KEY_FONT_FAMILY(StyleConstants.FontFamily.toString(), DEFAULT_FONT.getFamily()); + + String keyStr = ""; + String defaultStr = ""; + + FONT_PREFS (String keyStr, String defaultStr) + { + this.keyStr = keyStr; + this.defaultStr = defaultStr; + } + } + /** * Used to initialize some values that may throw exceptions. */ diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 7db1758..8b77ea8 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -953,6 +953,7 @@ public void run() fontDialog.getFontPanel().setDefaultFont(f); lineFormatter.setFont((StyledDocument) channelTextArea.getDocument(), fontDialog.getFontPanel().getFont()); + lineFormatter.updateStyles((StyledDocument) channelTextArea.getDocument(), 0); } }); } else @@ -967,7 +968,7 @@ private class SaveFontListener implements ActionListener public void actionPerformed(ActionEvent arg0) { // fontDialog.saveFont(fontDialog.getFont()); - fontDialog.getFontPanel().setFont(fontDialog.getFontPanel().getFont(), true); + fontDialog.getFontPanel().setFont(fontDialog.getFontPanel().getStyle(), true); setFont(fontDialog.getFontPanel().getFont()); } } diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index dd8e1e5..2eb6149 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -377,25 +377,33 @@ private void appendString(StyledDocument doc, String insertedString, SimpleAttri public URStyle getStyleBase(String styleName, boolean load) { - switch (styleName) + // TODO: Might need to readjust this again? + URStyle currentStyle = formatterStyles.get(styleName).clone(); + if(load) { - case "mediumStyle": - return mediumStyle(load); - case "highStyle": - return highStyle(load); - case "nickStyle": - return nickStyle(load); - case "myStyle": - return myStyle(load); - case "lowStyle": - return lowStyle(load); - case "urlStyle": - return urlStyle(load); - case "channelStyle": - return channelStyle(load); - default: - return defaultStyle(null, true); + currentStyle.load(formatterPrefs); } + + return currentStyle; + // switch (styleName) + // { + // case "mediumStyle": + // return mediumStyle(load); + // case "highStyle": + // return highStyle(load); + // case "nickStyle": + // return nickStyle(load); + // case "myStyle": + // return myStyle(load); + // case "lowStyle": + // return lowStyle(load); + // case "urlStyle": + // return urlStyle(load); + // case "channelStyle": + // return channelStyle(load); + // default: + // return defaultStyle(null, true); + // } } /** @@ -423,7 +431,7 @@ private void updateDocStyles(StyledDocument doc, int startPosition) int styleStart = startPosition; int styleLength = Integer.parseInt(textStyle.getAttribute("styleLength").toString()); - SimpleAttributeSet matchingStyle = getStyleBase(styleName, true); + SimpleAttributeSet matchingStyle = getStyleBase(styleName, false); boolean isDateStyle = false; if (null != DriverGUI.gui && null != textStyle.getAttribute("date")) @@ -505,7 +513,7 @@ private void updateDocStyles(StyledDocument doc, int startPosition) doc.setCharacterAttributes(styleStart, styleLength, matchingStyle, true); if ((styleStart + styleLength) < doc.getLength()) - updateStyles(doc, (styleStart + styleLength)); + updateDocStyles(doc, (styleStart + styleLength)); } public String getLatestLine(StyledDocument doc) throws BadLocationException diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index a022eea..cc501ed 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -1195,7 +1195,7 @@ public void actionPerformed(ActionEvent arg0) IRCRoomBase tabRoom = (IRCRoomBase) tab; if (tabRoom.getServer().getName().equals(favServer) && tabRoom.getName().equals(favChannel)) { - tabRoom.getFontPanel().setFont(favFontDialog.getFontPanel().getFont(), true); + tabRoom.getFontPanel().setFont(favFontDialog.getFontPanel().getStyle(), true); tabRoom.setFont(favFontDialog.getFontPanel().getFont()); } } diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 77c2138..13375d2 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -8,8 +8,11 @@ import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; +import java.awt.font.TextAttribute; import java.util.ArrayList; +import java.util.Hashtable; import java.util.List; +import java.util.Map; import java.util.prefs.Preferences; import javax.swing.*; import urChatBasic.frontend.dialogs.ColourDialog; @@ -55,7 +58,7 @@ public FontPanel(String styleName, URStyle defaultStyle, Preferences settingsPat targetStyle = new URStyle(styleName, defaultStyle.getFont()); this.defaultStyle = defaultStyle; setDefaultFont(targetStyle.getFont()); - + colourDialog = new ColourDialog(styleName, defaultStyle, settingsPath); RESET_BUTTON.addActionListener(new ResetListener()); COLOUR_BUTTON.addActionListener(new ActionListener() { @@ -65,7 +68,7 @@ public void actionPerformed(ActionEvent arg0) { if(colourDialog == null) { - colourDialog = new ColourDialog(styleName, defaultStyle, settingsPath); + ; colourDialog.getColourPanel().addSaveListener(e -> { // URPreferencesUtil.saveStyle(targetStyle, settingsPath); @@ -86,6 +89,7 @@ public void actionPerformed(ActionEvent arg0) SIZES_COMBO_BOX.addItemListener(new FontSelectionChange()); MAKE_BOLD.addActionListener(new CheckListener()); MAKE_ITALIC.addActionListener(new CheckListener()); + MAKE_UNDERLINE.addActionListener(new CheckListener()); // Reset the GridBagConstraints for MAIN_PANEL GridBagConstraints c = new GridBagConstraints(); @@ -171,7 +175,7 @@ public URStyle getStyle() // the UserGUI is Constants.DEFAULT_FONT public void resetFont() { URPreferencesUtil.deleteStyleFont(targetStyle, settingsPath); - + setStyle(defaultStyle); loadStyle(); } @@ -193,17 +197,20 @@ public void setFont(Font f) public void setStyle(URStyle newStyle) { - targetStyle = newStyle; + targetStyle = newStyle.clone(); - setFont(targetStyle.getFont(), false); + setFont(targetStyle, false); } - public void setFont(Font newFont, Boolean saveToSettings) + public void setFont(URStyle newStyle, Boolean saveToSettings) { + Font newFont = newStyle.getFont(); + if (getFont() != newFont || saveToSettings) { MAKE_BOLD.setSelected(newFont.isBold()); MAKE_ITALIC.setSelected(newFont.isItalic()); + MAKE_UNDERLINE.setSelected(newStyle.isUnderline()); FONT_COMBO_BOX.setSelectedItem(newFont.getFamily()); SIZES_COMBO_BOX.setSelectedItem(newFont.getSize()); @@ -222,21 +229,27 @@ public void setFont(Font newFont, Boolean saveToSettings) } } + //https://docs.oracle.com/javase/6/docs/api/java/awt/font/TextAttribute.html private void previewFont() { - int boldItalic = 0; + Map fontMap = new Hashtable(); if (MAKE_BOLD.isSelected()) - boldItalic = Font.BOLD; + fontMap.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); if (MAKE_ITALIC.isSelected()) - boldItalic |= Font.ITALIC; + fontMap.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + if (MAKE_UNDERLINE.isSelected()) + fontMap.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); setFont( new Font(FONT_COMBO_BOX.getSelectedItem().toString(), - boldItalic, + Font.PLAIN, Integer.parseInt(SIZES_COMBO_BOX.getSelectedItem().toString()) - )); + ).deriveFont(fontMap) + ); + + targetStyle.setFont(getFont()); } // Override the addActionListener method to keep track of added listeners @@ -277,7 +290,8 @@ class SaveListener implements ActionListener @Override public void actionPerformed(ActionEvent e) { - FontPanel.this.setFont(TEXT_PREVIEW.getFont(), true); + // FontPanel.this.setFont(TEXT_PREVIEW.getFont(), true); + setFont(targetStyle, true); } } From e37ffff9bbb22eeb8e261620c5297822c73d915c Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 10 Dec 2023 07:57:17 +1000 Subject: [PATCH 69/78] Properly loads defaults --- src/urChatBasic/base/IRCRoomBase.java | 3 +- src/urChatBasic/frontend/LineFormatter.java | 53 ++++++++++--------- src/urChatBasic/frontend/UserGUI.java | 2 +- .../frontend/components/ColourPanel.java | 6 +-- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 8b77ea8..d1e46b6 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -953,7 +953,8 @@ public void run() fontDialog.getFontPanel().setDefaultFont(f); lineFormatter.setFont((StyledDocument) channelTextArea.getDocument(), fontDialog.getFontPanel().getFont()); - lineFormatter.updateStyles((StyledDocument) channelTextArea.getDocument(), 0); + // TODO: Should this updateStyles if the font is changed? + // lineFormatter.updateStyles((StyledDocument) channelTextArea.getDocument(), 0); } }); } else diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 2eb6149..332ae09 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -375,7 +375,30 @@ private void appendString(StyledDocument doc, String insertedString, SimpleAttri insertString(doc, insertedString, style, position); } - public URStyle getStyleBase(String styleName, boolean load) + public URStyle getStyleDefault(String styleName) + { + switch (styleName) + { + case "mediumStyle": + return mediumStyle(false); + case "highStyle": + return highStyle(false); + case "nickStyle": + return nickStyle(false); + case "myStyle": + return myStyle(false); + case "lowStyle": + return lowStyle(false); + case "urlStyle": + return urlStyle(false); + case "channelStyle": + return channelStyle(false); + default: + return defaultStyle(null, true); + } + } + + public URStyle getStyle(String styleName, boolean load) { // TODO: Might need to readjust this again? URStyle currentStyle = formatterStyles.get(styleName).clone(); @@ -385,25 +408,7 @@ public URStyle getStyleBase(String styleName, boolean load) } return currentStyle; - // switch (styleName) - // { - // case "mediumStyle": - // return mediumStyle(load); - // case "highStyle": - // return highStyle(load); - // case "nickStyle": - // return nickStyle(load); - // case "myStyle": - // return myStyle(load); - // case "lowStyle": - // return lowStyle(load); - // case "urlStyle": - // return urlStyle(load); - // case "channelStyle": - // return channelStyle(load); - // default: - // return defaultStyle(null, true); - // } + } /** @@ -416,7 +421,7 @@ public void updateStyles(StyledDocument doc, int startPosition) targetStyle.load(formatterPrefs); for (URStyle formatterStyle : formatterStyles.values()) { - formatterStyle = getStyleBase(formatterStyle.getName(), true); + formatterStyle = getStyle(formatterStyle.getName(), true); } System.out.println("Updating styles."); @@ -431,7 +436,7 @@ private void updateDocStyles(StyledDocument doc, int startPosition) int styleStart = startPosition; int styleLength = Integer.parseInt(textStyle.getAttribute("styleLength").toString()); - SimpleAttributeSet matchingStyle = getStyleBase(styleName, false); + SimpleAttributeSet matchingStyle = getStyle(styleName, false); boolean isDateStyle = false; if (null != DriverGUI.gui && null != textStyle.getAttribute("date")) @@ -458,7 +463,7 @@ private void updateDocStyles(StyledDocument doc, int startPosition) if (!hasTime) doc.setCharacterAttributes(styleStart, styleLength, textStyle, true); - SimpleAttributeSet timeStyle = getStyleBase(styleName, true); + SimpleAttributeSet timeStyle = getStyle(styleName, false); timeStyle.addAttribute("date", lineDate); timeStyle.addAttribute("type", "time"); insertString(doc, newTimeString, timeStyle, styleStart); @@ -473,7 +478,7 @@ private void updateDocStyles(StyledDocument doc, int startPosition) styleStart = startPosition; styleLength = Integer.parseInt(textStyle.getAttribute("styleLength").toString()); - matchingStyle = getStyleBase(styleName, true); + matchingStyle = getStyle(styleName, false); matchingStyle.addAttribute("date", lineDate); isDateStyle = false; diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index cc501ed..278117e 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -949,7 +949,7 @@ public void mouseClicked(MouseEvent mouseEvent) { String styleName = styleLabel.getText(); FontDialog styleFontDialog = new FontDialog(styleName, - previewLineFormatter.getStyleBase(styleName, false), getProfilePath()); + previewLineFormatter.getStyleDefault(styleName), getProfilePath()); styleFontDialog.addSaveListener(arg0 -> { // List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); diff --git a/src/urChatBasic/frontend/components/ColourPanel.java b/src/urChatBasic/frontend/components/ColourPanel.java index df30b40..fcf3ffe 100644 --- a/src/urChatBasic/frontend/components/ColourPanel.java +++ b/src/urChatBasic/frontend/components/ColourPanel.java @@ -88,6 +88,7 @@ public JPanel createBottomPanel() resetButton.addActionListener(e -> { // URPreferencesUtil.deleteStyleColours(targetStyle, settingsPath); // defaultStyle.load(settingsPath); + URPreferencesUtil.deleteStyleColours(targetStyle, settingsPath); previewLabel.setFont(defaultStyle.getFont()); setPreviewColour(defaultStyle.getForeground(), true); setPreviewColour(defaultStyle.getBackground(), false); @@ -125,10 +126,7 @@ private void setPreviewColour (Color newColour, boolean setForeground) targetStyle.setForeground(newColour); } else { - if(newColour != targetStyle.getBackground()) - previewLabel.setOpaque(true); - else - previewLabel.setOpaque(false); + previewLabel.setOpaque(true); previewLabel.setBackground(newColour); targetStyle.setBackground(newColour); From 857f5ae620b56f8de0b933b26af35009e93da327 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 10 Dec 2023 08:10:54 +1000 Subject: [PATCH 70/78] Fix up removing favourites --- src/urChatBasic/frontend/UserGUI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 278117e..ce1cc84 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -1704,7 +1704,7 @@ public void cleanUpSettings() for (String profileNode : getProfilePath().childrenNames()) { - if (getProfilePath().node(profileNode).keys().length == 0) + if (getProfilePath().node(profileNode) != getFavouritesPath() && getProfilePath().node(profileNode).keys().length == 0) { getProfilePath().node(profileNode).removeNode(); } From af726341a84bebba1952e29d736fc11959b69009 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 11 Dec 2023 05:37:15 +1000 Subject: [PATCH 71/78] Change Printlns to use the Logger --- src/urChatBasic/backend/LookAndFeelLoader.java | 4 ++-- src/urChatBasic/backend/utils/URPreferencesUtil.java | 11 +++++------ src/urChatBasic/frontend/IRCServer.java | 2 +- src/urChatBasic/frontend/LineFormatter.java | 2 +- src/urChatBasic/frontend/components/FontPanel.java | 4 +++- src/urChatBasic/frontend/dialogs/ColourDialog.java | 1 - 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/urChatBasic/backend/LookAndFeelLoader.java b/src/urChatBasic/backend/LookAndFeelLoader.java index b9e640f..8d1e24d 100644 --- a/src/urChatBasic/backend/LookAndFeelLoader.java +++ b/src/urChatBasic/backend/LookAndFeelLoader.java @@ -71,12 +71,12 @@ public LookAndFeelLoader(ClassLoader parentLoader) throws IOException { try { UIManager.installLookAndFeel(classShortName, className); } catch (Exception installEx) { - System.out.println(installEx.getMessage()); + Constants.LOGGER.log(Level.WARNING, installEx.getMessage()); } } } } catch (NoClassDefFoundError | Exception classEx) { - System.out.println(classEx.getMessage()); + Constants.LOGGER.log(Level.WARNING, classEx.getMessage()); } } } diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index d97216e..fdc5cd0 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -6,6 +6,7 @@ import java.util.HashMap; import java.util.Hashtable; import java.util.Map; +import java.util.logging.Level; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import javax.swing.UIManager; @@ -99,11 +100,9 @@ else if (DriverGUI.gui != null) e.printStackTrace(); } - System.out.println("Load Style Path: " + stylePrefPath.toString()); + Constants.LOGGER.log(Level.INFO, "Load Style Path: " + stylePrefPath.toString()); Font loadedFont = loadStyleFont(targetStyle.getFont(), stylePrefPath); - // LineFormatter.getStyleAsFont(defaultStyle); Map loadedColours = loadStyleColours(targetStyle, stylePrefPath); - // LineFormatter.getStyleColours(defaultStyle); targetStyle.setFont(loadedFont); targetStyle.setForeground(loadedColours.get(Constants.KEY_FONT_FOREGROUND)); @@ -117,7 +116,7 @@ public static void deleteStyleFont(URStyle targetStyle, Preferences baseSettings Preferences settingsPath = baseSettingsPath.node(targetStyle.getName()); try { - System.out.println("Removing font keys: " + settingsPath.absolutePath()); + Constants.LOGGER.log(Level.INFO, "Removing font keys: " + settingsPath.absolutePath()); settingsPath.remove(Constants.KEY_FONT_BOLD); settingsPath.remove(Constants.KEY_FONT_ITALIC); settingsPath.remove(Constants.KEY_FONT_FAMILY); @@ -135,7 +134,7 @@ public static void deleteStyleColours(URStyle targetStyle, Preferences baseSetti Preferences settingsPath = baseSettingsPath.node(targetStyle.getName()); try { - System.out.println("Removing font colours: " + settingsPath.absolutePath()); + Constants.LOGGER.log(Level.INFO, "Removing font colours: " + settingsPath.absolutePath()); settingsPath.remove(Constants.KEY_FONT_FOREGROUND); settingsPath.remove(Constants.KEY_FONT_BACKGROUND); } catch (Exception e) @@ -148,7 +147,7 @@ public static void deleteStyleColours(URStyle targetStyle, Preferences baseSetti public static void saveStyle(URStyle targetStyle, Preferences baseSettingsPath) { Preferences stylePrefPath = baseSettingsPath.node(targetStyle.getAttribute("name").toString()); - System.out.println("Save Style Path: " + stylePrefPath.toString()); + Constants.LOGGER.log(Level.INFO, "Save Style Path: " + stylePrefPath.toString()); saveStyleFont(targetStyle.getFont(), stylePrefPath); saveStyleColours(targetStyle.getForeground(), targetStyle.getBackground(), stylePrefPath); } diff --git a/src/urChatBasic/frontend/IRCServer.java b/src/urChatBasic/frontend/IRCServer.java index f987417..d6cfb2d 100644 --- a/src/urChatBasic/frontend/IRCServer.java +++ b/src/urChatBasic/frontend/IRCServer.java @@ -280,7 +280,7 @@ public void actionPerformed(ActionEvent arg0) { if (IRCServer.this.isConnected()) { - System.out.println("send quit message"); + Constants.LOGGER.log(Level.INFO, "send quit message"); // Send the /quit message, which disconnects and remove the gui elements sendClientText("/quit Goodbye cruel world", getName()); } else diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 332ae09..418bb11 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -424,7 +424,7 @@ public void updateStyles(StyledDocument doc, int startPosition) formatterStyle = getStyle(formatterStyle.getName(), true); } - System.out.println("Updating styles."); + Constants.LOGGER.log(Level.INFO, "Updating styles."); updateDocStyles(doc, startPosition); } diff --git a/src/urChatBasic/frontend/components/FontPanel.java b/src/urChatBasic/frontend/components/FontPanel.java index 13375d2..1d1ddb4 100644 --- a/src/urChatBasic/frontend/components/FontPanel.java +++ b/src/urChatBasic/frontend/components/FontPanel.java @@ -13,11 +13,13 @@ import java.util.Hashtable; import java.util.List; import java.util.Map; +import java.util.logging.Level; import java.util.prefs.Preferences; import javax.swing.*; import urChatBasic.frontend.dialogs.ColourDialog; import urChatBasic.backend.utils.URPreferencesUtil; import urChatBasic.backend.utils.URStyle; +import urChatBasic.base.Constants; public class FontPanel extends JPanel { @@ -72,7 +74,7 @@ public void actionPerformed(ActionEvent arg0) colourDialog.getColourPanel().addSaveListener(e -> { // URPreferencesUtil.saveStyle(targetStyle, settingsPath); - System.out.println("Font Panel says: Save Colour pressed"); + Constants.LOGGER.log(Level.INFO, "Font Panel says: Save Colour pressed"); }); for (ActionListener actionListener : actionListeners) { diff --git a/src/urChatBasic/frontend/dialogs/ColourDialog.java b/src/urChatBasic/frontend/dialogs/ColourDialog.java index dbaacee..631800d 100644 --- a/src/urChatBasic/frontend/dialogs/ColourDialog.java +++ b/src/urChatBasic/frontend/dialogs/ColourDialog.java @@ -46,7 +46,6 @@ public ColourPanel getColourPanel() @Override public void setVisible(boolean shown) { - System.out.println("Colour Dialog visible = " + shown); if (!shown) colourPanel.loadStyle(); else From b157b85b9afa30b6fd6b7ebdd2f5ee15ae68d739 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 11 Dec 2023 05:44:35 +1000 Subject: [PATCH 72/78] Fixes #72 --- src/urChatBasic/frontend/LineFormatter.java | 28 ++++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index 418bb11..bfbc884 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -663,27 +663,31 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse String timeLine = UserGUI.getTimeLineString(lineDate); final URStyle nickPositionStyle; final URStyle linePositionStyle; + final URStyle timePositionStyle; if (fromUser != null && null != myNick && myNick.equals(fromUser.toString())) { // This message is from me - nickPositionStyle = myStyle; - linePositionStyle = lineStyle; + nickPositionStyle = myStyle.clone(); + linePositionStyle = lineStyle.clone(); + timePositionStyle = timeStyle.clone(); } else if (fromUser == null && fromString.equals(Constants.EVENT_USER)) { // This is an event message - nickPositionStyle = lowStyle; - linePositionStyle = lowStyle; + nickPositionStyle = lowStyle.clone(); + linePositionStyle = lowStyle.clone(); + timePositionStyle = lowStyle.clone(); } else { // This message is from someone else // Does this message have my nick in it? if (myNick != null && line.indexOf(myNick) > -1) - nickPositionStyle = highStyle; + nickPositionStyle = highStyle.clone(); else - nickPositionStyle = nickStyle; + nickPositionStyle = nickStyle.clone(); - linePositionStyle = lineStyle; + linePositionStyle = lineStyle.clone(); + timePositionStyle = timeStyle.clone(); } try @@ -695,11 +699,11 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse { // add the date to the end of the string to preserve the timestamp of the line // when updating styles - timeStyle.addAttribute("date", lineDate); - timeStyle.removeAttribute("type"); - timeStyle.addAttribute("type", "time"); - appendString(doc, timeLine + " ", timeStyle); - timeStyle.removeAttribute("type"); + timePositionStyle.addAttribute("date", lineDate); + timePositionStyle.removeAttribute("type"); + timePositionStyle.addAttribute("type", "time"); + appendString(doc, timeLine + " ", timePositionStyle); + timePositionStyle.removeAttribute("type"); linePositionStyle.removeAttribute("date"); } else { From 852fec77fe3bfd1faa73074e000df145bef7e485 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 11 Dec 2023 06:08:09 +1000 Subject: [PATCH 73/78] Sets an expected timeLineFormat for testing. --- src/urChatBasic/frontend/UserGUI.java | 5 +++++ tests/backend/MessageHandlerTests.java | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index ce1cc84..34b6ce1 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -1014,6 +1014,11 @@ public static String getTimeLineString(Date date) return chatDateFormat.format(date); } + public static void setTimeLineString(String newFormat) + { + timeStampField.setText(newFormat); + } + private void setupInterfacePanel() { interfacePanel.add(showEventTicker); diff --git a/tests/backend/MessageHandlerTests.java b/tests/backend/MessageHandlerTests.java index de42b1f..40fc88b 100644 --- a/tests/backend/MessageHandlerTests.java +++ b/tests/backend/MessageHandlerTests.java @@ -38,6 +38,7 @@ public void setUp() throws Exception { DriverGUI.createGUI(); testGUI = DriverGUI.gui; + UserGUI.setTimeLineString("[HHmm]"); testServer = new IRCServer("testServer", "testUser", "testUser", "testPassword", "1337", true, "testProxy", "1234", true); testUser = new IRCUser(testServer, "testUser"); @@ -92,7 +93,7 @@ public void noticeMessageParseTest(@Optional("someChannel") String channelName) @Test(groups = {"Test #003"}, timeOut = 5000) - public void nickIsDefaultStyleTest() throws BadLocationException, InterruptedException + public void nickIsNickStyleTest() throws BadLocationException, InterruptedException { String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG #somechannel :Welcome to somechannel!"; Message testMessage = testHandler.new Message(rawMessage); @@ -105,12 +106,12 @@ public void nickIsDefaultStyleTest() throws BadLocationException, InterruptedExc TimeUnit.SECONDS.sleep(1); } - // Should be defaultStyle because the user didn't mention testUser and is just a normal message - assertEquals("defaultStyle", + // Should be nickStyle because the user didn't mention testUser and is just a normal message + assertEquals("nickStyle", testChannel.getLineFormatter().getStyleAtPosition(testDoc, 11, testLine).getAttribute("name")); } - @Test(groups = {"Test #003"}, dependsOnMethods = {"backend.MessageHandlerTests.nickIsDefaultStyleTest"}) + @Test(groups = {"Test #003"}, dependsOnMethods = {"backend.MessageHandlerTests.nickIsNickStyleTest"}) public void sendActionMessageChannel() { String rawMessage = "/me claps hands"; From 2775825a181ada99f777992898a9a6faeaff99ad Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 11 Dec 2023 06:18:18 +1000 Subject: [PATCH 74/78] change to run all tests --- build/test-build-linux.sh | 2 +- build/testng_release.xml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 build/testng_release.xml diff --git a/build/test-build-linux.sh b/build/test-build-linux.sh index b6c38aa..a6dcf54 100755 --- a/build/test-build-linux.sh +++ b/build/test-build-linux.sh @@ -65,7 +65,7 @@ cd "$temp_dir" mkdir -p "report" # run with jacoco agent to build coverage.exec -java -javaagent:lib/coverage/jacocoagent.jar=destfile=coverage.exec -cp "urchat.jar:urTestRunner.jar" org.testng.TestNG ./build/testng.xml +java -javaagent:lib/coverage/jacocoagent.jar=destfile=coverage.exec -cp "urchat.jar:urTestRunner.jar" org.testng.TestNG ./build/testng_release.xml # build html report pointing to the source .java files java -jar lib/coverage/jacococli.jar report coverage.exec --classfiles urchat.jar --html report --sourcefiles src/ diff --git a/build/testng_release.xml b/build/testng_release.xml new file mode 100644 index 0000000..0c916e9 --- /dev/null +++ b/build/testng_release.xml @@ -0,0 +1,8 @@ + + + + + + + + From 9a1da3d37bd6010ec92694797538f366dd03d649 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 11 Dec 2023 06:26:53 +1000 Subject: [PATCH 75/78] Update the test xml --- build/testng_release.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/testng_release.xml b/build/testng_release.xml index 0c916e9..a90cd1f 100644 --- a/build/testng_release.xml +++ b/build/testng_release.xml @@ -2,7 +2,7 @@ - + From 2903697f8ca6b756e8716b883b21d5ec416a1d2a Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 11 Dec 2023 06:39:11 +1000 Subject: [PATCH 76/78] Some changes to pass on Windows --- tests/backend/MessageHandlerTests.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/backend/MessageHandlerTests.java b/tests/backend/MessageHandlerTests.java index 40fc88b..e8aad3b 100644 --- a/tests/backend/MessageHandlerTests.java +++ b/tests/backend/MessageHandlerTests.java @@ -240,8 +240,8 @@ public void testChannelLineLimit() throws BadLocationException, InterruptedExcep assertTrue( "First line should be line # 10 but it was " - + testChannel.getChannelTextPane().getText().split("\n")[0], - testChannel.getChannelTextPane().getText().split("\n")[0].endsWith("line # 10")); + + testChannel.getChannelTextPane().getText().split(System.lineSeparator())[0], + testChannel.getChannelTextPane().getText().split(System.lineSeparator())[0].trim().endsWith("line # 10")); assertSame("Channel line count should equal the line limit", channelLinesLimit, channelLinesCount - 1); } @@ -275,8 +275,8 @@ public void testServerLineLimit() throws BadLocationException, InterruptedExcept assertTrue("Last line should line # 19 but it was" + testLine, testLine.endsWith("line # 19")); assertTrue( - "First line should be line # 10 but it was " + testServer.getChannelTextPane().getText().split("\n")[0], - testServer.getChannelTextPane().getText().split("\n")[0].endsWith("line # 10")); + "First line should be line # 10 but it was " + testServer.getChannelTextPane().getText().split(System.lineSeparator())[0], + testServer.getChannelTextPane().getText().split(System.lineSeparator())[0].trim().endsWith("line # 10")); assertSame("Channel line count should equal the line limit", serverLinesLimit, serverLinesCount - 1); } From b8c73cf64b0a4fcf7abef31669271d1893a342df Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 12 Dec 2023 06:02:31 +1000 Subject: [PATCH 77/78] Adds the UIManagerDefaults again, for testing only. Adjust all calls to UIManager to use the constants string instead. LineFormatter sets the background to be the background selected in Constants. --- src/urChatBasic/UIManagerDefaults.java | 747 ++++++++++++++++++ .../backend/utils/URPreferencesUtil.java | 4 +- src/urChatBasic/backend/utils/URStyle.java | 5 +- src/urChatBasic/base/Constants.java | 2 + src/urChatBasic/base/IRCRoomBase.java | 6 +- src/urChatBasic/frontend/LineFormatter.java | 20 +- src/urChatBasic/frontend/UserGUI.java | 10 +- 7 files changed, 775 insertions(+), 19 deletions(-) create mode 100644 src/urChatBasic/UIManagerDefaults.java diff --git a/src/urChatBasic/UIManagerDefaults.java b/src/urChatBasic/UIManagerDefaults.java new file mode 100644 index 0000000..0ec91a2 --- /dev/null +++ b/src/urChatBasic/UIManagerDefaults.java @@ -0,0 +1,747 @@ +package urChatBasic; +/* + * This programs uses the information found in the UIManager + * to create a table of key/value pairs for each Swing component. + */ + +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; +import java.util.*; +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.plaf.*; +import javax.swing.table.*; + +public class UIManagerDefaults implements ActionListener, ItemListener +{ + private final static String[] COLUMN_NAMES = {"Key", "Value", "Sample"}; + private static String selectedItem; + + private JComponent contentPane; + private JMenuBar menuBar; + private JComboBox comboBox; + private JRadioButton byComponent; + private JTable table; + private TreeMap> items; + private HashMap models; + + /* + * Constructor + */ + public UIManagerDefaults() + { + items = new TreeMap>(); + models = new HashMap(); + + contentPane = new JPanel( new BorderLayout() ); + contentPane.add(buildNorthComponent(), BorderLayout.NORTH); + contentPane.add(buildCenterComponent(), BorderLayout.CENTER); + + resetComponents(); + } + + /* + * The content pane should be added to a high level container + */ + public JComponent getContentPane() + { + return contentPane; + } + + /* + * A menu can also be added which provides the ability to switch + * between different LAF's. + */ + public JMenuBar getMenuBar() + { + if (menuBar == null) + menuBar = createMenuBar(); + + return menuBar; + } + + /* + * This panel is added to the North of the content pane + */ + private JComponent buildNorthComponent() + { + comboBox = new JComboBox(); + + JLabel label = new JLabel("Select Item:"); + label.setDisplayedMnemonic('S'); + label.setLabelFor( comboBox ); + + byComponent = new JRadioButton("By Component", true); + byComponent.setMnemonic('C'); + byComponent.addActionListener( this ); + + JRadioButton byValueType = new JRadioButton("By Value Type"); + byValueType.setMnemonic('V'); + byValueType.addActionListener( this ); + + ButtonGroup group = new ButtonGroup(); + group.add(byComponent); + group.add(byValueType); + + JPanel panel = new JPanel(); + panel.setBorder( new EmptyBorder(15, 0, 15, 0) ); + panel.add( label ); + panel.add( comboBox ); + panel.add( byComponent ); + panel.add( byValueType ); + return panel; + } + + /* + * This panel is added to the Center of the content pane + */ + private JComponent buildCenterComponent() + { + DefaultTableModel model = new DefaultTableModel(COLUMN_NAMES, 0); + table = new JTable(model); + table.setAutoCreateColumnsFromModel( false ); + table.getColumnModel().getColumn(0).setPreferredWidth(250); + table.getColumnModel().getColumn(1).setPreferredWidth(500); + table.getColumnModel().getColumn(2).setPreferredWidth(100); + table.getColumnModel().getColumn(2).setCellRenderer( new SampleRenderer() ); + Dimension d = table.getPreferredSize(); + d.height = 350; + table.setPreferredScrollableViewportSize( d ); + + return new JScrollPane( table ); + } + + /* + * When the LAF is changed we need to reset the content pane + */ + public void resetComponents() + { + items.clear(); + models.clear(); + ((DefaultTableModel)table.getModel()).setRowCount(0); + + buildItemsMap(); + + Vector comboBoxItems = new Vector(50); + Iterator keys = items.keySet().iterator(); + + while (keys.hasNext()) + { + Object key = keys.next(); + comboBoxItems.add( (String)key ); + } + + comboBox.removeItemListener( this ); + comboBox.setModel( new DefaultComboBoxModel( comboBoxItems ) ); + comboBox.setSelectedIndex(-1); + comboBox.addItemListener( this ); + comboBox.requestFocusInWindow(); + + if (selectedItem != null) + comboBox.setSelectedItem(selectedItem); + } + + /* + * The item map will contain items for each component or + * items for each attribute type. + */ + private TreeMap buildItemsMap() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + // Build of Map of items and a Map of attributes for each item + + for ( Enumeration enumm = defaults.keys(); enumm.hasMoreElements(); ) + { + Object key = enumm.nextElement(); + Object value = defaults.get( key ); + + String itemName = getItemName(key.toString(), value); + + if (itemName == null) continue; + + // Get the attribute map for this componenent, or + // create a map when one is not found + + TreeMap attributeMap = items.get( itemName ); + + if (attributeMap == null) + { + attributeMap = new TreeMap(); + items.put(itemName, attributeMap); + } + + // Add the attribute to the map for this componenent + + attributeMap.put(key.toString(), value ); + } + + return items; + } + + /* + * Parse the key to determine the item name to use + */ + private String getItemName(String key, Object value) + { + // Seems like this is an old check required for JDK1.4.2 + + if (key.startsWith("class") || key.startsWith("javax")) + return null; + + if (byComponent.isSelected()) + return getComponentName(key, value); + else + return getValueName(key, value); + } + + private String getComponentName(String key, Object value) + { + // The key is of the form: + // "componentName.componentProperty", or + // "componentNameUI", or + // "someOtherString" + + String componentName; + + int pos = componentNameEndOffset( key ); + + if (pos != -1) + { + componentName = key.substring( 0, pos ); + } + else if (key.endsWith( "UI" ) ) + { + componentName = key.substring( 0, key.length() - 2 ); + } + else if (value instanceof ColorUIResource) + { + componentName = "System Colors"; + } + else + { + componentName = "Miscellaneous"; + } + + // Fix inconsistency + + if (componentName.equals("Checkbox")) + { + componentName = "CheckBox"; + } + + return componentName; + } + + private int componentNameEndOffset(String key) + { + // Handle Nimbus properties first + + // "ComboBox.scrollPane", "Table.editor" and "Tree.cellEditor" + // have different format even within the Nimbus properties. + // (the component name is specified in quotes) + + if (key.startsWith("\"")) + return key.indexOf("\"", 1) + 1; + + int pos = key.indexOf( ":" ); + + if (pos != -1) + return pos; + + pos = key.indexOf( "[" ); + + if (pos != -1) + return pos; + + // Handle normal properties + + return key.indexOf( "." ); + } + + private String getValueName(String key, Object value) + { + if (value instanceof Icon) + return "Icon"; + else if (value instanceof Font) + return "Font"; + else if (value instanceof Border) + return "Border"; + else if (value instanceof Color) + return "Color"; + else if (value instanceof Insets) + return "Insets"; + else if (value instanceof Boolean) + return "Boolean"; + else if (value instanceof Dimension) + return "Dimension"; + else if (value instanceof Number) + return "Number"; + else if (value instanceof Painter) + return "Painter"; + else if (key.endsWith("UI")) + return "UI"; + else if (key.endsWith("InputMap")) + return "InputMap"; + else if (key.endsWith("RightToLeft")) + return "InputMap"; + else if (key.endsWith("radient")) + return "Gradient"; + else + { + return "The Rest"; + } + } + + /** + * Create menu bar + */ + private JMenuBar createMenuBar() + { + JMenuBar menuBar = new JMenuBar(); + + menuBar.add( createFileMenu() ); + menuBar.add( createLAFMenu() ); + + return menuBar; + } + + /** + * Create menu items for the Application menu + */ + private JMenu createFileMenu() + { + JMenu menu = new JMenu("Application"); + menu.setMnemonic('A'); + + menu.addSeparator(); + menu.add( new ExitAction() ); + + return menu; + } + + /** + * Create menu items for the Look & Feel menu + */ + private JMenu createLAFMenu() + { + ButtonGroup bg = new ButtonGroup(); + + JMenu menu = new JMenu("Look & Feel"); + menu.setMnemonic('L'); + + String lafId = UIManager.getLookAndFeel().getID(); + UIManager.LookAndFeelInfo[] lafInfo = UIManager.getInstalledLookAndFeels(); + + for (int i = 0; i < lafInfo.length; i++) + { + String laf = lafInfo[i].getClassName(); + String name= lafInfo[i].getName(); + + Action action = new ChangeLookAndFeelAction(this, laf, name); + JRadioButtonMenuItem mi = new JRadioButtonMenuItem( action ); + menu.add( mi ); + bg.add( mi ); + + if (name.equals(lafId)) + { + mi.setSelected(true); + } + } + + return menu; + } + + /* + * Implement the ActionListener interface + */ + public void actionPerformed(ActionEvent e) + { + selectedItem = null; + resetComponents(); + comboBox.requestFocusInWindow(); + } + + /* + * Implement the ItemListener interface + */ + public void itemStateChanged(ItemEvent e) + { + String itemName = (String)e.getItem(); + changeTableModel( itemName ); + updateRowHeights(); + selectedItem = itemName; + } + + /* + * Change the TabelModel in the table for the selected item + */ + private void changeTableModel(String itemName) + { + // The model has been created previously so just use it + + DefaultTableModel model = models.get( itemName ); + + if (model != null) + { + table.setModel( model ); + return; + } + + // Create a new model for the requested item + // and add the attributes of the item to the model + + model = new DefaultTableModel(COLUMN_NAMES, 0); + Map attributes = (Map)items.get( itemName ); + + Iterator ai = attributes.keySet().iterator(); + + while (ai.hasNext()) + { + String attribute = (String)ai.next(); + Object value = attributes.get(attribute); + + Vector row = new Vector(3); + row.add(attribute); + + if (value != null) + { + row.add( value.toString() ); + + if (value instanceof Icon) + value = new SafeIcon( (Icon)value ); + + row.add( value ); + } + else + { + row.add( "null" ); + row.add( "" ); + } + + model.addRow( row ); + } + + table.setModel( model ); + models.put(itemName, model); + } + + /* + * Some rows containing icons, may need to be sized taller to fully + * display the icon. + */ + private void updateRowHeights() + { + for (int row = 0; row < table.getRowCount(); row++) + { + int rowHeight = table.getRowHeight(); + + for (int column = 0; column < table.getColumnCount(); column++) + { + Component comp = table.prepareRenderer(table.getCellRenderer(row, column), row, column); + rowHeight = Math.max(rowHeight, comp.getPreferredSize().height); + } + + table.setRowHeight(row, rowHeight); + } + } + + /** + * Thanks to Jeanette for the use of this code found at: + * + * https://jdnc-incubator.dev.java.net/source/browse/jdnc-incubator/src/kleopatra/java/org/jdesktop/swingx/renderer/UIPropertiesViewer.java?rev=1.2&view=markup + * + * Some ui-icons misbehave in that they unconditionally class-cast to the + * component type they are mostly painted on. Consequently they blow up if + * we are trying to paint them anywhere else (f.i. in a renderer). + * + * This Icon is an adaption of a cool trick by Darryl Burke found at + * http://tips4java.wordpress.com/2008/12/18/icon-table-cell-renderer + * + * The base idea is to instantiate a component of the type expected by the icon, + * let it paint into the graphics of a bufferedImage and create an ImageIcon from it. + * In subsequent calls the ImageIcon is used. + * + */ + public static class SafeIcon implements Icon + { + private Icon wrappee; + private Icon standIn; + + public SafeIcon(Icon wrappee) + { + this.wrappee = wrappee; + } + + @Override + public int getIconHeight() + { + return wrappee.getIconHeight(); + } + + @Override + public int getIconWidth() + { + return wrappee.getIconWidth(); + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) + { + if (standIn == this) + { + paintFallback(c, g, x, y); + } + else if (standIn != null) + { + standIn.paintIcon(c, g, x, y); + } + else + { + try + { + wrappee.paintIcon(c, g, x, y); + } + catch (ClassCastException e) + { + createStandIn(e, x, y); + standIn.paintIcon(c, g, x, y); + } + } + } + + /** + * @param e + */ + private void createStandIn(ClassCastException e, int x, int y) + { + try + { + Class clazz = getClass(e); + JComponent standInComponent = getSubstitute(clazz); + standIn = createImageIcon(standInComponent, x, y); + } + catch (Exception e1) + { + // something went wrong - fallback to this painting + standIn = this; + } + } + + private Icon createImageIcon(JComponent standInComponent, int x, int y) + { + BufferedImage image = new BufferedImage(getIconWidth(), getIconHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics g = image.createGraphics(); + try + { + wrappee.paintIcon(standInComponent, g, 0, 0); + return new ImageIcon(image); + } + finally + { + g.dispose(); + } + } + + /** + * @param clazz + * @throws IllegalAccessException + */ + private JComponent getSubstitute(Class clazz) throws IllegalAccessException + { + JComponent standInComponent; + + try + { + standInComponent = (JComponent) clazz.newInstance(); + } + catch (InstantiationException e) + { + standInComponent = new AbstractButton() {}; + ((AbstractButton) standInComponent).setModel(new DefaultButtonModel()); + } + return standInComponent; + } + + private Class getClass(ClassCastException e) throws ClassNotFoundException + { + String className = e.getMessage(); + className = className.substring(className.lastIndexOf(" ") + 1); + return Class.forName(className); + + } + + private void paintFallback(Component c, Graphics g, int x, int y) + { + g.drawRect(x, y, getIconWidth(), getIconHeight()); + g.drawLine(x, y, x + getIconWidth(), y + getIconHeight()); + g.drawLine(x + getIconWidth(), y, x, y + getIconHeight()); + } + + } + + + /* + * Render the value based on its class. + */ + class SampleRenderer extends JLabel implements TableCellRenderer + { + public SampleRenderer() + { + super(); + setHorizontalAlignment( SwingConstants.CENTER ); + setOpaque(true); + } + + public Component getTableCellRendererComponent( + JTable table, Object sample, boolean isSelected, boolean hasFocus, int row, int column) + { + setBackground( null ); + setBorder( null ); + setIcon( null ); + setText( "" ); + + if ( sample instanceof Color ) + { + setBackground( (Color)sample ); + } + else if ( sample instanceof Border ) + { + setBorder( (Border)sample ); + } + else if ( sample instanceof Font ) + { + setText( "Sample" ); + setFont( (Font)sample ); + } + else if ( sample instanceof Icon ) + { + setIcon( (Icon)sample ); + } + + return this; + } + + /* + * Some icons are painted using inner classes and are not meant to be + * shared by other items. This code will catch the + * ClassCastException that is thrown. + */ + public void paint(Graphics g) + { + try + { + super.paint(g); + } + catch(Exception e) + { +// System.out.println(e); +// System.out.println(e.getStackTrace()[0]); + } + } + } + + /* + * Change the LAF and recreate the UIManagerDefaults so that the properties + * of the new LAF are correctly displayed. + */ + class ChangeLookAndFeelAction extends AbstractAction + { + private UIManagerDefaults defaults; + private String laf; + + protected ChangeLookAndFeelAction(UIManagerDefaults defaults, String laf, String name) + { + this.defaults = defaults; + this.laf = laf; + putValue(Action.NAME, name); + putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME)); + } + + public void actionPerformed(ActionEvent e) + { + try + { + UIManager.setLookAndFeel( laf ); + defaults.resetComponents(); + + JMenuItem mi = (JMenuItem) e.getSource(); + JPopupMenu popup = (JPopupMenu) mi.getParent(); + JRootPane rootPane = SwingUtilities.getRootPane( popup.getInvoker() ); + SwingUtilities.updateComponentTreeUI( rootPane ); + + // Use custom decorations when supported by the LAF + + JFrame frame = (JFrame)SwingUtilities.windowForComponent(rootPane); + frame.dispose(); + + if (UIManager.getLookAndFeel().getSupportsWindowDecorations()) + { + frame.setUndecorated(true); + frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME); + } + else + { + frame.setUndecorated(false); + } + + frame.setVisible(true); + } + catch (Exception ex) + { + System.out.println("Failed loading L&F: " + laf); + System.out.println(ex); + } + } + } + + /* + * Close the frame + */ + class ExitAction extends AbstractAction + { + public ExitAction() + { + putValue(Action.NAME, "Exit"); + putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME)); + putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_X)); + } + + public void actionPerformed(ActionEvent e) + { + System.exit(0); + } + } + + /* + * Build a GUI using the content pane and menu bar of UIManagerDefaults + */ + public static void createAndShowGUI() + { + UIManagerDefaults application = new UIManagerDefaults(); + + JFrame.setDefaultLookAndFeelDecorated(true); + JFrame frame = new JFrame("UIManager Defaults"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setJMenuBar( application.getMenuBar() ); + frame.getContentPane().add(application.getContentPane()); + frame.pack(); + frame.setLocationRelativeTo( null ); + frame.setVisible( true ); + } + + /* + * UIManagerDefaults Main. Called only if we're an application. + */ + public static void main(String[] args) + { + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + createAndShowGUI(); + } + }); + } +} diff --git a/src/urChatBasic/backend/utils/URPreferencesUtil.java b/src/urChatBasic/backend/utils/URPreferencesUtil.java index fdc5cd0..5751bdd 100644 --- a/src/urChatBasic/backend/utils/URPreferencesUtil.java +++ b/src/urChatBasic/backend/utils/URPreferencesUtil.java @@ -177,8 +177,8 @@ private static void saveStyleFont(Font newFont, Preferences settingsPath) private static void saveStyleColours(Color foreground, Color background, Preferences settingsPath) { // Don't save if it's the default colours - Color defaultForeground = UIManager.getColor("Label.foreground"); - Color defaultBackground = UIManager.getColor("Panel.background"); + Color defaultForeground = UIManager.getColor(Constants.DEFAULT_FOREGROUND_STRING); + Color defaultBackground = UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING); if(URColour.hexEncode(defaultForeground).equals(URColour.hexEncode(foreground))) { diff --git a/src/urChatBasic/backend/utils/URStyle.java b/src/urChatBasic/backend/utils/URStyle.java index 4458083..6f15ee8 100644 --- a/src/urChatBasic/backend/utils/URStyle.java +++ b/src/urChatBasic/backend/utils/URStyle.java @@ -9,6 +9,7 @@ import javax.swing.UIManager; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; +import urChatBasic.base.Constants; public class URStyle extends SimpleAttributeSet { @@ -31,8 +32,8 @@ public URStyle(String name, Font defaultFont) super(); this.addAttribute("name", name); setFont(defaultFont); - setForeground(UIManager.getColor("Label.foreground")); - setBackground(UIManager.getColor("Panel.background")); + setForeground(UIManager.getColor(Constants.DEFAULT_FOREGROUND_STRING)); + setBackground(UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING)); } /** diff --git a/src/urChatBasic/base/Constants.java b/src/urChatBasic/base/Constants.java index 6328ba2..2e79cea 100644 --- a/src/urChatBasic/base/Constants.java +++ b/src/urChatBasic/base/Constants.java @@ -36,6 +36,8 @@ public class Constants public static String LOGFILE_NAME = "Errors.log"; private static final JLabel DEFAULT_LABEL = new JLabel(); private static final Font DEFAULT_FONT = new Font(DEFAULT_LABEL.getFont().getFamily(), 0, DEFAULT_LABEL.getFont().getSize()); + public static final String DEFAULT_FOREGROUND_STRING = "TextArea.foreground"; + public static final String DEFAULT_BACKGROUND_STRING = "TextArea.background"; // Preferences public static final Preferences BASE_PREFS = Preferences.userNodeForPackage(DriverGUI.class).node("profiles"); diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index d1e46b6..9915d4d 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -173,13 +173,13 @@ private void initRoom() roomPrefs = gui.getFavouritesPath().node(getServer().getName()).node(roomName); fontDialog = new FontDialog(roomName, gui.getStyle(), roomPrefs); - lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getStyle(), channelTextArea , getServer(), roomPrefs); } else { roomPrefs = gui.getFavouritesPath().node(roomName); fontDialog = new FontDialog(roomName, gui.getStyle(), roomPrefs); - lineFormatter = new LineFormatter(getFontPanel().getStyle() , null, roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , channelTextArea, null, roomPrefs); } setFont(getFontPanel().getFont()); @@ -240,7 +240,7 @@ public FontPanel getFontPanel() public void resetLineFormatter() { - lineFormatter = new LineFormatter(getFontPanel().getStyle() , getServer(), roomPrefs); + lineFormatter = new LineFormatter(getFontPanel().getStyle() , channelTextArea, getServer(), roomPrefs); } private void setupMainTextArea() diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index bfbc884..e65ecbe 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -18,6 +18,7 @@ import javax.swing.AbstractAction; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; +import javax.swing.JTextPane; import javax.swing.UIManager; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; @@ -47,15 +48,21 @@ public class LineFormatter private URStyle highStyle; private URStyle mediumStyle; private URStyle lowStyle; + private JTextPane docOwner; public URStyle myStyle; private Map formatterStyles = new HashMap<>(); - public LineFormatter(URStyle baseStyle, final IRCServerBase server, Preferences formatterPrefs) + public LineFormatter(URStyle baseStyle, JTextPane docOwner ,final IRCServerBase server, Preferences formatterPrefs) { // TODO: Need to load attributes from formatterPrefs this.formatterPrefs = formatterPrefs; + this.docOwner = docOwner; + + // The JTextPane is technically 'disabled', so we need to change the colour to be the enabled colour. + this.docOwner.setBackground(UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING)); + if (null != server) { myNick = server.getNick(); @@ -113,7 +120,7 @@ public URStyle defaultStyle(String name, boolean load) // get the contrasting colour of the background colour // StyleConstants.setForeground(defaultStyle, new Color(formatterPrefs.node(name).getInt("font // foreground", - // URColour.getContrastColour(UIManager.getColor("Panel.background")).getRGB()))); + // URColour.getContrastColour(UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING)).getRGB()))); StyleConstants.setFontFamily(tempStyle, targetStyle.getFont().getFamily()); StyleConstants.setFontSize(tempStyle, targetStyle.getFont().getSize()); @@ -121,7 +128,6 @@ public URStyle defaultStyle(String name, boolean load) StyleConstants.setItalic(tempStyle, targetStyle.getFont().isItalic()); StyleConstants.setForeground(tempStyle, myForeground); - StyleConstants.setBackground(tempStyle, myBackground); if (load) tempStyle.load(formatterPrefs); @@ -136,15 +142,15 @@ public URStyle lowStyle(boolean load) URStyle tempStyle = defaultStyle(name, load); - StyleConstants.setForeground(tempStyle, UIManager.getColor("Panel.background").darker()); + StyleConstants.setForeground(tempStyle, UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING).darker()); if (StyleConstants.getForeground(tempStyle).getRGB() == myForeground.getRGB()) - if (URColour.useDarkColour(UIManager.getColor("Panel.background"))) + if (URColour.useDarkColour(UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING))) { - StyleConstants.setForeground(tempStyle, UIManager.getColor("Panel.background").darker()); + StyleConstants.setForeground(tempStyle, UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING).darker()); } else { - StyleConstants.setForeground(tempStyle, UIManager.getColor("Panel.background").brighter()); + StyleConstants.setForeground(tempStyle, UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING).brighter()); } if (load) diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 34b6ce1..91cad79 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -910,7 +910,7 @@ public void updatePreviewTextArea() // } // previewTextArea.setFont(clientFontPanel.getFont()); - previewLineFormatter = new LineFormatter(clientFontPanel.getStyle(), null, getProfilePath()); + previewLineFormatter = new LineFormatter(clientFontPanel.getStyle(), previewTextArea , null, getProfilePath()); if (previewDoc.getLength() <= 0) { @@ -1996,8 +1996,8 @@ private LookAndFeelInfo getLAF(String lafClassName) private void setNewLAF(String newLAFname) { - Color previousDefaultForeground = UIManager.getColor("Label.foreground"); - Color previousDefaultBackground = UIManager.getColor("Panel.background"); + Color previousDefaultForeground = UIManager.getColor(Constants.DEFAULT_FOREGROUND_STRING); + Color previousDefaultBackground = UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING); Font previousDefaultFont = getFont(); // System.out.println("Setting to "+newLAFname); @@ -2044,10 +2044,10 @@ private void setNewLAF(String newLAFname) // reset the defaults on the guiStyle if they were already at the default if (previousDefaultForeground == guiStyle.getForeground()) - guiStyle.setForeground(UIManager.getColor("Label.foreground")); + guiStyle.setForeground(UIManager.getColor(Constants.DEFAULT_FOREGROUND_STRING)); if (previousDefaultBackground == guiStyle.getBackground()) - guiStyle.setBackground(UIManager.getColor("Panel.background")); + guiStyle.setBackground(UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING)); SwingUtilities.updateComponentTreeUI(DriverGUI.frame); updateExtras(); From e8bee1c2912146da6fac1e1da2599b81dbb03c25 Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 12 Dec 2023 06:35:29 +1000 Subject: [PATCH 78/78] Remove references to 'doc', this is instead set when LineFormatter is initialized. --- src/urChatBasic/base/IRCRoomBase.java | 11 +-- src/urChatBasic/frontend/LineFormatter.java | 93 ++++++++++++++------- src/urChatBasic/frontend/UserGUI.java | 22 ++--- tests/backend/MessageHandlerTests.java | 38 ++++----- 4 files changed, 96 insertions(+), 68 deletions(-) diff --git a/src/urChatBasic/base/IRCRoomBase.java b/src/urChatBasic/base/IRCRoomBase.java index 9915d4d..452b9de 100644 --- a/src/urChatBasic/base/IRCRoomBase.java +++ b/src/urChatBasic/base/IRCRoomBase.java @@ -256,6 +256,8 @@ private void setupMainTextArea() channelTextArea.setEditable(false); channelTextArea.setFont(getFontPanel().getFont()); channelTextArea.setEditorKit(new StyledEditorKit()); + // This is needed because the channelTextArea isn't the same after it was initialized. + resetLineFormatter(); } private void setupUsersList() @@ -458,8 +460,8 @@ public void run() String line = messagePair.getLine(); String fromUser = messagePair.getUser(); - Document document = channelTextArea.getDocument(); - Element root = document.getDefaultRootElement(); + Document document = lineFormatter.getDocument(); + Element root = lineFormatter.getDocument().getDefaultRootElement(); int lineLimit = gui.getLimitChannelLinesCount(); @@ -519,7 +521,7 @@ public void run() if (fromUser.equals(Constants.EVENT_USER) || !fromIRCUser.isMuted()) { - lineFormatter.formattedDocument(doc, new Date(), fromIRCUser, fromUser, line); + lineFormatter.formattedDocument(new Date(), fromIRCUser, fromUser, line); if (server.getNick() != null && line.indexOf(server.getNick()) > -1) { @@ -951,8 +953,7 @@ public void run() { fontDialog.getFontPanel().setDefaultFont(f); - lineFormatter.setFont((StyledDocument) channelTextArea.getDocument(), - fontDialog.getFontPanel().getFont()); + lineFormatter.setFont(fontDialog.getFontPanel().getFont()); // TODO: Should this updateStyles if the font is changed? // lineFormatter.updateStyles((StyledDocument) channelTextArea.getDocument(), 0); } diff --git a/src/urChatBasic/frontend/LineFormatter.java b/src/urChatBasic/frontend/LineFormatter.java index e65ecbe..b6b82c5 100644 --- a/src/urChatBasic/frontend/LineFormatter.java +++ b/src/urChatBasic/frontend/LineFormatter.java @@ -49,6 +49,7 @@ public class LineFormatter private URStyle mediumStyle; private URStyle lowStyle; private JTextPane docOwner; + private StyledDocument doc; public URStyle myStyle; private Map formatterStyles = new HashMap<>(); @@ -62,6 +63,7 @@ public LineFormatter(URStyle baseStyle, JTextPane docOwner ,final IRCServerBase // The JTextPane is technically 'disabled', so we need to change the colour to be the enabled colour. this.docOwner.setBackground(UIManager.getColor(Constants.DEFAULT_BACKGROUND_STRING)); + doc = this.docOwner.getStyledDocument(); if (null != server) { @@ -103,11 +105,11 @@ public LineFormatter(URStyle baseStyle, JTextPane docOwner ,final IRCServerBase formatterStyles.put(lowStyle.getName(), lowStyle); } - public void setFont(StyledDocument doc, Font newFont) + public void setFont(Font newFont) { targetStyle.setFont(newFont); if (doc.getLength() > 0) - updateStyles(doc, 0); + updateStyles(0); } public URStyle defaultStyle(String name, boolean load) @@ -359,7 +361,7 @@ public void actionPerformed(ActionEvent e) } // Inserts the string at the position - private void insertString(StyledDocument doc, String insertedString, SimpleAttributeSet style, int position) + private void insertString(String insertedString, SimpleAttributeSet style, int position) throws BadLocationException { // remove the existing attributes @@ -373,12 +375,12 @@ private void insertString(StyledDocument doc, String insertedString, SimpleAttri } // Adds the string (with all needed attributes) to the end of the document - private void appendString(StyledDocument doc, String insertedString, SimpleAttributeSet style) + private void appendString(String insertedString, SimpleAttributeSet style) throws BadLocationException { int position = doc.getLength(); - insertString(doc, insertedString, style, position); + insertString(insertedString, style, position); } public URStyle getStyleDefault(String styleName) @@ -419,10 +421,9 @@ public URStyle getStyle(String styleName, boolean load) /** * Reloads all the styles, then updates the doc - * @param doc * @param startPosition */ - public void updateStyles(StyledDocument doc, int startPosition) + public void updateStyles(int startPosition) { targetStyle.load(formatterPrefs); @@ -431,10 +432,10 @@ public void updateStyles(StyledDocument doc, int startPosition) } Constants.LOGGER.log(Level.INFO, "Updating styles."); - updateDocStyles(doc, startPosition); + updateDocStyles(startPosition); } - private void updateDocStyles(StyledDocument doc, int startPosition) + private void updateDocStyles(int startPosition) { SimpleAttributeSet textStyle = new SimpleAttributeSet(doc.getCharacterElement(startPosition).getAttributes()); @@ -472,7 +473,7 @@ private void updateDocStyles(StyledDocument doc, int startPosition) SimpleAttributeSet timeStyle = getStyle(styleName, false); timeStyle.addAttribute("date", lineDate); timeStyle.addAttribute("type", "time"); - insertString(doc, newTimeString, timeStyle, styleStart); + insertString(newTimeString, timeStyle, styleStart); styleLength = newTimeString.length(); } else { @@ -524,10 +525,37 @@ private void updateDocStyles(StyledDocument doc, int startPosition) doc.setCharacterAttributes(styleStart, styleLength, matchingStyle, true); if ((styleStart + styleLength) < doc.getLength()) - updateDocStyles(doc, (styleStart + styleLength)); + updateDocStyles((styleStart + styleLength)); } - public String getLatestLine(StyledDocument doc) throws BadLocationException + public String getFirstLine() throws BadLocationException + { + Element root = doc.getDefaultRootElement(); + int linePos = 0; + + String finalLine = ""; + + while (finalLine.isEmpty()) + { + + if (linePos < 0) + break; + + Element line = root.getElement(linePos++); + + if (null == line) + continue; + + int start = line.getStartOffset(); + int end = line.getEndOffset(); + String text = doc.getText(start, end - start); + finalLine = text.trim(); + } + + return finalLine; + } + + public String getLatestLine() throws BadLocationException { Element root = doc.getDefaultRootElement(); int lines = root.getElementCount(); @@ -554,7 +582,7 @@ public String getLatestLine(StyledDocument doc) throws BadLocationException return finalLine; } - private int getLinePosition(StyledDocument doc, String targetLine) throws BadLocationException + private int getLinePosition(String targetLine) throws BadLocationException { Element root = doc.getDefaultRootElement(); int lines = root.getElementCount(); @@ -579,25 +607,25 @@ private int getLinePosition(StyledDocument doc, String targetLine) throws BadLoc return 0; } - public SimpleAttributeSet getStyleAtPosition(StyledDocument doc, int position, String relativeLine) + public SimpleAttributeSet getStyleAtPosition(int position, String relativeLine) throws BadLocationException { if (!relativeLine.isBlank()) - position = position + getLinePosition(doc, relativeLine); + position = position + getLinePosition(relativeLine); AttributeSet textStyle = doc.getCharacterElement(position).getAttributes(); return new SimpleAttributeSet(textStyle); } - private void parseClickableText(StyledDocument doc, IRCUser fromUser, String line, URStyle defaultStyle) + private void parseClickableText(IRCUser fromUser, String line, URStyle defaultStyle) throws BadLocationException { HashMap regexStrings = new HashMap<>(); regexStrings.put(Constants.URL_REGEX, urlStyle); regexStrings.put(Constants.CHANNEL_REGEX, channelStyle); // final String line = getLatestLine(doc); - final int relativePosition = getLinePosition(doc, getLatestLine(doc)); + final int relativePosition = getLinePosition(getLatestLine()); ArrayList clickableLines = new ArrayList(); @@ -645,25 +673,23 @@ private void parseClickableText(StyledDocument doc, IRCUser fromUser, String lin int nextLineLength = Integer.parseInt(nextLine.getAttribute("styleLength").toString()); // Append the string that comes before the next clickable text - appendString(doc, remainingLine.substring(0, nextLineStart - offset), defaultStyle); + appendString(remainingLine.substring(0, nextLineStart - offset), defaultStyle); - appendString(doc, nextLine.getAttribute("clickableText").toString(), nextLine); + appendString(nextLine.getAttribute("clickableText").toString(), nextLine); remainingLine = remainingLine.substring((nextLineStart + nextLineLength) - offset); } - appendString(doc, remainingLine, defaultStyle); + appendString(remainingLine, defaultStyle); } /** * Inserts a string onto the end of the doc. - * - * @param doc - * @param timeLine * @param fromUser * @param line + * @param timeLine */ - public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUser, String fromString, String line) + public void formattedDocument(Date lineDate, IRCUser fromUser, String fromString, String line) { // build the timeLine string String timeLine = UserGUI.getTimeLineString(lineDate); @@ -708,7 +734,7 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse timePositionStyle.addAttribute("date", lineDate); timePositionStyle.removeAttribute("type"); timePositionStyle.addAttribute("type", "time"); - appendString(doc, timeLine + " ", timePositionStyle); + appendString(timeLine + " ", timePositionStyle); timePositionStyle.removeAttribute("type"); linePositionStyle.removeAttribute("date"); } else @@ -716,7 +742,7 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse linePositionStyle.addAttribute("date", lineDate); } - appendString(doc, "<", linePositionStyle); + appendString("<", linePositionStyle); linePositionStyle.removeAttribute("date"); if (fromUser != null) @@ -727,25 +753,30 @@ public void formattedDocument(StyledDocument doc, Date lineDate, IRCUser fromUse new ClickableText(fromUser.toString(), nickPositionStyle, fromUser)); // doc.insertString(doc.getLength(), fromUser.toString(), clickableNameStyle); - appendString(doc, fromUser.toString(), clickableNameStyle); + appendString(fromUser.toString(), clickableNameStyle); } else { - appendString(doc, fromString, nickPositionStyle); + appendString(fromString, nickPositionStyle); } - appendString(doc, ">", linePositionStyle); + appendString(">", linePositionStyle); // print the remaining text // appendString(doc, " "+line, lineStyle); // parse the outputted line for clickable text - parseClickableText(doc, fromUser, " " + line, linePositionStyle); + parseClickableText(fromUser, " " + line, linePositionStyle); - appendString(doc, System.getProperty("line.separator"), linePositionStyle); + appendString(System.getProperty("line.separator"), linePositionStyle); } catch (BadLocationException e) { Constants.LOGGER.log(Level.SEVERE, e.getLocalizedMessage()); } } + public StyledDocument getDocument() + { + return doc; + } + } diff --git a/src/urChatBasic/frontend/UserGUI.java b/src/urChatBasic/frontend/UserGUI.java index 91cad79..c18ee9f 100644 --- a/src/urChatBasic/frontend/UserGUI.java +++ b/src/urChatBasic/frontend/UserGUI.java @@ -920,19 +920,14 @@ public void updatePreviewTextArea() IRCUser tempUser = new IRCUser(null, "matty_r"); IRCUser tempUser2 = new IRCUser(null, System.getProperty("user.name")); previewLineFormatter.setNick(System.getProperty("user.name")); - previewLineFormatter.formattedDocument(previewDoc, new Date(), null, Constants.EVENT_USER, - "urChat has loaded - this is an Event"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", - "Normal line. Hello, world!"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser, "matty_r", - "This is what it looks like when your nick is mentioned, " + System.getProperty("user.name") + "!"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), - "Go to https://github.com/matty-r/urChat"); - previewLineFormatter.formattedDocument(previewDoc, new Date(), tempUser2, System.getProperty("user.name"), - "Join #urchatclient on irc.libera.chat or #anotherroom"); + previewLineFormatter.formattedDocument(new Date(), null, Constants.EVENT_USER, "urChat has loaded - this is an Event"); + previewLineFormatter.formattedDocument(new Date(), tempUser, "matty_r", "Normal line. Hello, world!"); + previewLineFormatter.formattedDocument(new Date(), tempUser, "matty_r", "This is what it looks like when your nick is mentioned, " + System.getProperty("user.name") + "!"); + previewLineFormatter.formattedDocument(new Date(), tempUser2, System.getProperty("user.name"), "Go to https://github.com/matty-r/urChat"); + previewLineFormatter.formattedDocument(new Date(), tempUser2, System.getProperty("user.name"), "Join #urchatclient on irc.libera.chat or #anotherroom"); } else { - previewLineFormatter.updateStyles(previewDoc, 0); + previewLineFormatter.updateStyles(0); } } @@ -955,7 +950,7 @@ public void mouseClicked(MouseEvent mouseEvent) // List actionListeners = styleFontDialog.getFontPanel().getActionListeners(); // TODO: Need to save attributes and updateStyles after.. // Currently runs the save after updateStyles - previewLineFormatter.updateStyles(doc, 0); + previewLineFormatter.updateStyles(0); }); // styleFontDialog.addResetListener(new ActionListener() { @@ -1901,7 +1896,7 @@ public void actionPerformed(ActionEvent arg0) } // previewLineFormatter.setFont(previewTextArea.getStyledDocument(), clientFontPanel.getFont()); - previewLineFormatter.updateStyles(previewTextArea.getStyledDocument(), 0); + previewLineFormatter.updateStyles(0); } } @@ -2070,6 +2065,7 @@ private void updateExtras() ((IRCRoomBase) tab).getFontPanel().setDefaultFont(clientFontPanel.getFont()); SwingUtilities.updateComponentTreeUI(((IRCRoomBase) tab).myMenu); SwingUtilities.updateComponentTreeUI(((IRCRoomBase) tab).getFontPanel()); + // TODO: Update styles ((IRCRoomBase) tab).getChannelTextPane() } } diff --git a/tests/backend/MessageHandlerTests.java b/tests/backend/MessageHandlerTests.java index e8aad3b..2599743 100644 --- a/tests/backend/MessageHandlerTests.java +++ b/tests/backend/MessageHandlerTests.java @@ -54,8 +54,7 @@ public void nickIsHighStyleTest() throws BadLocationException, InterruptedExcept String rawMessage = ":someuser!~someuser@urchatclient PRIVMSG testUser :hello testUser!"; Message testMessage = testHandler.new Message(rawMessage); testHandler.parseMessage(testMessage); - StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); - String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] hello testUser!" + String testLine = testChannel.getLineFormatter().getLatestLine(); // "[0629] hello testUser!" while (testChannel.messageQueueWorking()) { @@ -64,7 +63,7 @@ public void nickIsHighStyleTest() throws BadLocationException, InterruptedExcept // Should be highStyle because someuser mentioned my nick, testUser assertEquals("highStyle", - testChannel.getLineFormatter().getStyleAtPosition(testDoc, 11, testLine).getAttribute("name")); + testChannel.getLineFormatter().getStyleAtPosition(11, testLine).getAttribute("name")); } @Test(groups = {"Test #001"}) @@ -99,7 +98,7 @@ public void nickIsNickStyleTest() throws BadLocationException, InterruptedExcept Message testMessage = testHandler.new Message(rawMessage); testHandler.parseMessage(testMessage); StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); - String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] hello world!" + String testLine = testChannel.getLineFormatter().getLatestLine(); // "[0629] hello world!" while (testChannel.messageQueueWorking()) { @@ -108,7 +107,7 @@ public void nickIsNickStyleTest() throws BadLocationException, InterruptedExcept // Should be nickStyle because the user didn't mention testUser and is just a normal message assertEquals("nickStyle", - testChannel.getLineFormatter().getStyleAtPosition(testDoc, 11, testLine).getAttribute("name")); + testChannel.getLineFormatter().getStyleAtPosition(11, testLine).getAttribute("name")); } @Test(groups = {"Test #003"}, dependsOnMethods = {"backend.MessageHandlerTests.nickIsNickStyleTest"}) @@ -231,17 +230,19 @@ public void testChannelLineLimit() throws BadLocationException, InterruptedExcep // int serverLinesCount = // testServer.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); int channelLinesCount = - testChannel.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); + testChannel.getLineFormatter().getDocument().getDefaultRootElement().getElementCount(); - StyledDocument testDoc = testChannel.getChannelTextPane().getStyledDocument(); - String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // " line # 509" - assertTrue("Last line should line # 19 but it was" + testLine, testLine.endsWith("line # 19")); + + String firstLine = testChannel.getLineFormatter().getFirstLine(); + String lastLine = testChannel.getLineFormatter().getLatestLine(); // " line # 509" + + assertTrue("Last line should line # 19 but it was" + lastLine, lastLine.endsWith("line # 19")); assertTrue( "First line should be line # 10 but it was " - + testChannel.getChannelTextPane().getText().split(System.lineSeparator())[0], - testChannel.getChannelTextPane().getText().split(System.lineSeparator())[0].trim().endsWith("line # 10")); + + firstLine, + firstLine.endsWith("line # 10")); assertSame("Channel line count should equal the line limit", channelLinesLimit, channelLinesCount - 1); } @@ -269,8 +270,7 @@ public void testServerLineLimit() throws BadLocationException, InterruptedExcept int serverLinesCount = testServer.getChannelTextPane().getStyledDocument().getDefaultRootElement().getElementCount(); - StyledDocument testDoc = testServer.getChannelTextPane().getStyledDocument(); - String testLine = testServer.getLineFormatter().getLatestLine(testDoc); // " line # 19" + String testLine = testServer.getLineFormatter().getLatestLine(); // " line # 19" assertTrue("Last line should line # 19 but it was" + testLine, testLine.endsWith("line # 19")); @@ -306,11 +306,11 @@ public void urlInMessage() throws BadLocationException, InterruptedException TimeUnit.SECONDS.sleep(1); } - String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); // "[0629] + String testLine = testChannel.getLineFormatter().getLatestLine(); // "[0629] // https://google.com" // Should be urlStyle, i.e a clickable link assertEquals("urlStyle", - testChannel.getLineFormatter().getStyleAtPosition(testDoc, 19, testLine).getAttribute("name")); + testChannel.getLineFormatter().getStyleAtPosition(19, testLine).getAttribute("name")); } @Test @@ -354,13 +354,13 @@ public void channelInMessage() throws BadLocationException, InterruptedException TimeUnit.SECONDS.sleep(1); } - String testLine = testChannel.getLineFormatter().getLatestLine(testDoc); + String testLine = testChannel.getLineFormatter().getLatestLine(); // Should be channel, i.e clickable name which allows you to join the channel assertEquals("channelStyle", - testChannel.getLineFormatter().getStyleAtPosition(testDoc, 33, testLine).getAttribute("name")); + testChannel.getLineFormatter().getStyleAtPosition(33, testLine).getAttribute("name")); assertEquals("urlStyle", - testChannel.getLineFormatter().getStyleAtPosition(testDoc, 58, testLine).getAttribute("name")); + testChannel.getLineFormatter().getStyleAtPosition(58, testLine).getAttribute("name")); assertEquals("channelStyle", - testChannel.getLineFormatter().getStyleAtPosition(testDoc, 110, testLine).getAttribute("name")); + testChannel.getLineFormatter().getStyleAtPosition(110, testLine).getAttribute("name")); } }