diff --git a/src/main/java/dev/sillyangel/calc/utils/Utils.java b/src/main/java/dev/sillyangel/calc/utils/Utils.java new file mode 100644 index 0000000..470ddb0 --- /dev/null +++ b/src/main/java/dev/sillyangel/calc/utils/Utils.java @@ -0,0 +1,254 @@ +package dev.sillyangel.calc.utils; + +import javax.swing.JOptionPane; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.Toolkit; +import java.util.List; +import javax.swing.JTextArea; +import javax.swing.JScrollPane; +import javax.swing.JLabel; +import javax.swing.JButton; +import javax.swing.border.EmptyBorder; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.JDialog; +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.Font; +import dev.sillyangel.calc.Calculator; + +public class Utils { + // private double result; + // private boolean resultVisible; + private Calculator ci; + public Utils(Calculator ci) { + System.out.printf(""); + this.ci = ci; + } + + public void reciprocal() { + String tmp = ci.display.getText(); + if (tmp == null || tmp.isEmpty()) { + return; + } + try { + double value = Double.parseDouble(tmp); + if (value != 0) { + ci.result = 1.0 / value; + ci.display.setText("" + ci.result); + ci.resultVisible = true; + } else { + ci.display.setText("Error: Div by Zero"); + ci.resultVisible = false; + } + } catch (NumberFormatException e) { + ci.display.setText("Error: Invalid Input"); + ci.resultVisible = false; + } + } + + public void clearAll() { + ci.display.setText(""); + ci.operand1 = ""; + ci.operand2 = ""; + ci.operator = ""; + } + + public void square() { + String tmp = ci.display.getText(); + if (tmp == null || tmp.isEmpty()) return; + double value = Double.parseDouble(tmp); + ci.result = value * value; + ci.display.setText("" + ci.result); + ci.resultVisible = true; + } + + public void squareRoot() { + String tmp = ci.display.getText(); + if (tmp == null || tmp.isEmpty()) return; + double value = Double.parseDouble(tmp); + if (value >= 0) { + ci.result = Math.sqrt(value); + ci.display.setText("" + ci.result); + ci.resultVisible = true; + } + } + + public void backspace() { + String tmp = ci.display.getText(); + if (tmp.length()>1) // if there is more than 1 character + ci.display.setText( tmp.substring(0, tmp.length()-1) ); + else // otherwise just make display empty + ci.display.setText(""); + } + + public void math() { + ci.operand2 = ci.display.getText(); + double op1 = Double.parseDouble(ci.operand1); + double op2 = Double.parseDouble(ci.operand2); + + if ("+".equals(ci.operator)) { + ci.result = op1+op2; + } else if ("-".equals(ci.operator)) { + ci.result = op1-op2; + } else if ("*".equals(ci.operator)) { + ci.result = op1*op2; + } else if ("/".equals(ci.operator)) { + ci.result = op1/op2; + } else if ("%".equals(ci.operator)) { + ci.result = op1 % op2; + } else { + ci.result = op2; + System.out.println("Op: " + op1); + System.out.println("Op2: " + op2); + } + + // Save calculation to history + if (!ci.operator.isEmpty()) { + String calculation = ci.operand1 + " " + ci.operator + " " + ci.operand2 + " = " + ci.result; + ci.history.saveToHistory(calculation); + } + + ci.operator = ""; + ci.operand1 = ""; + ci.operand2 = ""; + + ci.resultVisible = true; + ci.display.setText(""+ci.result); + saveToUndoStack(""+ci.result); + } + + public void saveToUndoStack(String value) { + // Remove any states after current index (if user undid and then made a new action) + if (ci.undoIndex < ci.undoStack.size() - 1) { + ci.undoStack.subList(ci.undoIndex + 1, ci.undoStack.size()).clear(); + } + ci.undoStack.add(value); + ci.undoIndex = ci.undoStack.size() - 1; + } + public void undoAction() { + if (ci.undoIndex > 0) { + ci.undoIndex--; + ci.display.setText(ci.undoStack.get(ci.undoIndex)); + } else { + System.out.println("Nothing to undo"); + } + } + + public void redoAction() { + if (ci.undoIndex < ci.undoStack.size() - 1) { + ci.undoIndex++; + ci.display.setText(ci.undoStack.get(ci.undoIndex)); + } else { + System.out.println("Nothing to redo"); + } + } + + // Clipboard operations + public void cutAction() { + copyAction(); + ci.display.setText(""); + } + + public void copyAction() { + String text = ci.display.getText(); + if (text != null && !text.isEmpty()) { + StringSelection selection = new StringSelection(text); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(selection, null); + System.out.println("Copied: " + text); + } + } + + public void pasteAction() { + try { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + String text = (String) clipboard.getData(DataFlavor.stringFlavor); + if (text != null && !text.isEmpty()) { + // Validate that pasted content is a valid number + try { + Double.parseDouble(text); + ci.display.setText(text); + saveToUndoStack(text); + } catch (NumberFormatException ex) { + JOptionPane.showMessageDialog(ci, + "Pasted content is not a valid number", + "Invalid Input", JOptionPane.ERROR_MESSAGE); + } + } + } catch (Exception ex) { + System.err.println("Error pasting: " + ex.getMessage()); + } + } + public void processDigit(String actionCommand) { + if (ci.resultVisible) { + ci.display.setText(""); + ci.resultVisible = false; + } + String newValue = ci.display.getText() + actionCommand; + ci.display.setText(newValue); + saveToUndoStack(newValue); + } + public void setOperator(String daop) { + ci.operand1 = ci.display.getText(); + ci.operator = daop; + ci.display.setText(""); + } + public void clearEntry() { + ci.display.setText(""); + } + public void showHistoryDialog() { + JDialog historyDialog = new JDialog(this.ci, "Calculation History", true); + historyDialog.setSize(500, 400); + historyDialog.setLocationRelativeTo(this.ci); + historyDialog.setLayout(new BorderLayout(10, 10)); + + List historyList = ci.history.getCalculationHistory(); + + if (historyList.isEmpty()) { + JLabel emptyLabel = new JLabel("No calculation history yet", SwingConstants.CENTER); + emptyLabel.setFont(new Font("Segoe UI", Font.PLAIN, 14)); + historyDialog.add(emptyLabel, BorderLayout.CENTER); + } else { + JTextArea historyTextArea = new JTextArea(); + historyTextArea.setEditable(false); + historyTextArea.setFont(new Font("Monospaced", Font.PLAIN, 12)); + + StringBuilder historyText = new StringBuilder(); + for (String entry : historyList) { + historyText.append(entry).append("\n"); + } + historyTextArea.setText(historyText.toString()); + + JScrollPane scrollPane = new JScrollPane(historyTextArea); + historyDialog.add(scrollPane, BorderLayout.CENTER); + + // Status label + JLabel statusLabel = new JLabel("Total calculations: " + historyList.size()); + statusLabel.setBorder(new EmptyBorder(5, 10, 5, 10)); + historyDialog.add(statusLabel, BorderLayout.NORTH); + } + + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + JButton closeButton = new JButton("Close"); + closeButton.addActionListener(e -> historyDialog.dispose()); + buttonPanel.add(closeButton); + + historyDialog.add(buttonPanel, BorderLayout.SOUTH); + historyDialog.setVisible(true); + } + public void clearHistoryAction() { + int result = JOptionPane.showConfirmDialog(this.ci, + "Are you sure you want to clear all calculation history?", + "Clear History", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); + + if (result == JOptionPane.YES_OPTION) { + ci.history.clearHistory(); + JOptionPane.showMessageDialog(this.ci, + "History cleared successfully", + "Success", JOptionPane.INFORMATION_MESSAGE); + } + } +} \ No newline at end of file