Advertisement
Nickpips

Upwork Project

Jul 8th, 2016 (edited)
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 17.01 KB | None | 0 0
  1. import java.awt.AWTException;
  2. import java.awt.Color;
  3. import java.awt.Dimension;
  4. import java.awt.Font;
  5. import java.awt.Graphics;
  6. import java.awt.Image;
  7. import java.awt.MenuItem;
  8. import java.awt.PopupMenu;
  9. import java.awt.SystemTray;
  10. import java.awt.Toolkit;
  11. import java.awt.TrayIcon;
  12. import java.awt.event.ActionEvent;
  13. import java.awt.event.ActionListener;
  14. import java.awt.event.MouseEvent;
  15. import java.awt.event.MouseListener;
  16. import java.io.File;
  17. import java.io.FileOutputStream;
  18. import java.io.IOException;
  19. import java.io.PrintWriter;
  20. import java.text.DateFormat;
  21. import java.time.LocalDateTime;
  22. import java.util.ArrayList;
  23. import java.util.Date;
  24. import java.util.HashSet;
  25. import java.util.Locale;
  26. import java.util.Scanner;
  27. import java.util.logging.Level;
  28. import java.util.logging.Logger;
  29.  
  30. import javax.imageio.ImageIO;
  31. import javax.swing.AbstractAction;
  32. import javax.swing.ActionMap;
  33. import javax.swing.InputMap;
  34. import javax.swing.JComponent;
  35. import javax.swing.JDialog;
  36. import javax.swing.JLabel;
  37. import javax.swing.JLayeredPane;
  38. import javax.swing.JOptionPane;
  39. import javax.swing.JTextArea;
  40. import javax.swing.KeyStroke;
  41.  
  42. import org.jnativehook.GlobalScreen;
  43. import org.jnativehook.NativeHookException;
  44. import org.jnativehook.keyboard.NativeKeyEvent;
  45. import org.jnativehook.keyboard.NativeKeyListener;
  46.  
  47. public class Main implements MouseListener, ActionListener, NativeKeyListener {
  48.  
  49.     final private int width = 400;
  50.     final private int height = 400;
  51.  
  52.     private HashSet<Integer> pressedKeys = new HashSet<Integer>();
  53.     private String answer = null;
  54.     private JDialog frame;
  55.     private ImagePanel imagePanel;
  56.     private JLabel qLabel;
  57.     private JTextArea aLabel;
  58.     private String imgFilename;
  59.     private String iconFilename;
  60.     private ArrayList<Task> tasks;
  61.     private ArrayList<String> notes;
  62.     private PrintWriter log;
  63.     private Color bg;
  64.     private Color fg;
  65.     private int pt;
  66.     private int curTaskID;
  67.  
  68.     private void run(String[] args) throws InterruptedException {
  69.         // Initialize stuff
  70.         tasks = new ArrayList<Task>();
  71.         notes = new ArrayList<String>();
  72.         bg = new Color(0, 0, 0, 0);
  73.         fg = new Color(255, 0, 0, 255);
  74.         pt = 20;
  75.  
  76.         // Check if System Tray is supported
  77.         if (!SystemTray.isSupported()) {
  78.             System.err.println("System Tray is not supported");
  79.             return;
  80.         }
  81.  
  82.         // Parse the configuration file
  83.         try {
  84.             readConfig("./config");
  85.         } catch (Exception e) {
  86.             e.printStackTrace();
  87.             System.err.println("\nCould not open config file:");
  88.             System.err.println(e.getMessage());
  89.             return;
  90.         }
  91.  
  92.         // Read in the background image
  93.         Image bgImage = null;
  94.         try {
  95.             bgImage = ImageIO.read(new File(imgFilename)).getScaledInstance(width, height, Image.SCALE_DEFAULT);
  96.         } catch (IOException e) {
  97.             e.printStackTrace();
  98.             System.err.println("Could not read background image");
  99.             return;
  100.         }
  101.  
  102.         // Read in the background image
  103.         Image iconImage = null;
  104.         try {
  105.             iconImage = ImageIO.read(new File(iconFilename));
  106.         } catch (IOException e) {
  107.             e.printStackTrace();
  108.             System.err.println("Could not read icon image");
  109.             return;
  110.         }
  111.  
  112.         // Setup pop ups     for system tray
  113.         PopupMenu popup = new PopupMenu();
  114.         MenuItem timeItem = new MenuItem(getTime(0));
  115.         MenuItem refreshItem = new MenuItem("Refresh");
  116.         MenuItem exitItem = new MenuItem("Exit");
  117.         timeItem.setEnabled(false);
  118.         refreshItem.addActionListener(this);
  119.         exitItem.addActionListener(this);
  120.         popup.add(timeItem);
  121.         popup.add(refreshItem);
  122.         popup.add(exitItem);
  123.         popup.add(new MenuItem());
  124.  
  125.         // Setup system tray
  126.         SystemTray tray = SystemTray.getSystemTray();
  127.         TrayIcon trayIcon = new TrayIcon(iconImage);
  128.         trayIcon.setImageAutoSize(true);
  129.         trayIcon.setPopupMenu(popup);
  130.         try {
  131.             tray.add(trayIcon);
  132.         } catch (AWTException e) {
  133.             System.err.println("System tray icon could not be added");
  134.             return;
  135.         }
  136.        
  137.         // Initialize the JComponents
  138.         imagePanel = new ImagePanel(bgImage);
  139.         imagePanel.setSize(width, height);
  140.         imagePanel.addMouseListener(this);
  141.  
  142.         qLabel = new JLabel();
  143.         qLabel.setBackground(bg);
  144.         qLabel.setForeground(fg);
  145.         qLabel.setSize(width, height);
  146.  
  147.         aLabel = new JTextArea();
  148.         aLabel.setLineWrap(true);
  149.         InputMap input = aLabel.getInputMap();
  150.         KeyStroke enter = KeyStroke.getKeyStroke("ENTER");
  151.         KeyStroke shiftEnter = KeyStroke.getKeyStroke("shift ENTER");
  152.         input.put(shiftEnter, "shift ENTER");
  153.         input.put(enter, "ENTER");
  154.         ActionMap actions = aLabel.getActionMap();
  155.         actions.put("ENTER", new AbstractAction() {
  156.             private static final long serialVersionUID = 2845098944540081988L;
  157.  
  158.             @Override
  159.             public void actionPerformed(ActionEvent e) {
  160.                 answer = aLabel.getText();
  161.             }
  162.         });
  163.         actions.put("shift ENTER", new AbstractAction() {
  164.             private static final long serialVersionUID = -7395068805752131054L;
  165.  
  166.             @Override
  167.             public void actionPerformed(ActionEvent e) {
  168.                 aLabel.setText(aLabel.getText() + "\n");
  169.             }
  170.         });
  171.  
  172.         // Get screen dimensions
  173.         Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  174.         double W = screenSize.getWidth();
  175.         double H = screenSize.getHeight();
  176.  
  177.         // Define the look of the frame
  178.         frame = new JDialog();
  179.         frame.setUndecorated(true);
  180.         frame.setLocation((int) (W - width) / 2, (int) (H - height) / 2);
  181.         frame.setBackground(new Color(0, 0, 0, 0));
  182.         frame.setSize(width, height);
  183.         frame.setAlwaysOnTop(true);
  184.         frame.setVisible(false);
  185.  
  186.         // Continuously check for new tasks
  187.         while (true) {
  188.             // Get current time
  189.             int curTime = LocalDateTime.now().getHour() * 60 + LocalDateTime.now().getMinute();
  190.  
  191.             // bestTime = max, now minimize bestTime
  192.             int bestTime = curTime - 1;
  193.             Task bestTask = null;
  194.  
  195.             // Check all valid tasks
  196.             for (Task task : tasks) {
  197.                 // Check if it's tomorrow and task.start is better than
  198.                 // bestTime,
  199.                 // or if it's today and task.start is better than bestTime
  200.                 if ((bestTime < curTime && (curTime <= task.start || task.start <= bestTime))
  201.                         || (curTime < bestTime && curTime < task.start && task.start < bestTime)) {
  202.                     bestTime = task.start;
  203.                     bestTask = task;
  204.                 }
  205.                 if ((bestTime < curTime && (task.end >= curTime || task.end <= bestTime))
  206.                         || (curTime < bestTime && curTime < task.end && task.end < bestTime)) {
  207.                     bestTime = task.end;
  208.                     bestTask = task;
  209.                 }
  210.             }
  211.  
  212.             // Note the time in the label
  213.             timeItem.setLabel(getTime(bestTime));
  214.  
  215.             // Check every second to be precise
  216.             while (curTime != bestTime) {
  217.                 if (toRefresh) {
  218.                     tray.remove(trayIcon);
  219.                     return;
  220.                 }
  221.                 Thread.sleep(500);
  222.                 curTime = LocalDateTime.now().getHour() * 60 + LocalDateTime.now().getMinute();
  223.             }
  224.  
  225.             // Now process the task
  226.             processTask(bestTask, bestTime == bestTask.end);
  227.  
  228.             // In order to update the time on the tray
  229.             if (curTime == bestTime) {
  230.                 // Save values so we do not affect surrounding logic
  231.                 int oldCurTime = curTime;
  232.                 int oldBestTime = bestTime;
  233.  
  234.                 // Get current time
  235.                 curTime++;
  236.  
  237.                 // bestTime = max, now minimize bestTime
  238.                 bestTime = curTime - 1;
  239.                 bestTask = null;
  240.  
  241.                 // Check all valid tasks
  242.                 for (Task task : tasks) {
  243.                     // Check if it's tomorrow and task.start is better than
  244.                     // bestTime,
  245.                     // or if it's today and task.start is better than bestTime
  246.                     if ((bestTime < curTime && (curTime <= task.start || task.start <= bestTime))
  247.                             || (curTime < bestTime && curTime < task.start && task.start < bestTime)) {
  248.                         bestTime = task.start;
  249.                         bestTask = task;
  250.                     }
  251.                     if ((bestTime < curTime && (task.end >= curTime || task.end <= bestTime))
  252.                             || (curTime < bestTime && curTime < task.end && task.end < bestTime)) {
  253.                         bestTime = task.end;
  254.                         bestTask = task;
  255.                     }
  256.                 }
  257.  
  258.                 // Note the time in the label
  259.                 timeItem.setLabel(getTime(bestTime));
  260.  
  261.                 // Restore these values
  262.                 curTime = oldCurTime;
  263.                 bestTime = oldBestTime;
  264.             }
  265.  
  266.             // Wait until we move on
  267.             while (curTime == bestTime) {
  268.                 if (toRefresh) {
  269.                     tray.remove(trayIcon);
  270.                     return;
  271.                 }
  272.                 Thread.sleep(500);
  273.                 curTime = LocalDateTime.now().getHour() * 60 + LocalDateTime.now().getMinute();
  274.             }
  275.         }
  276.     }
  277.  
  278.     private void processTask(Task t, boolean end) throws InterruptedException {
  279.         frame.getLayeredPane().removeAll();
  280.         frame.getLayeredPane().add(qLabel);
  281.         frame.getLayeredPane().add(aLabel);
  282.         frame.getLayeredPane().add(imagePanel, JLayeredPane.DEFAULT_LAYER);
  283.  
  284.         for (Question q : t.questions) {
  285.             if (end && q.pre || !end && !q.pre)
  286.                 continue;
  287.  
  288.             String text = q.text;
  289.  
  290.             /*
  291.              * Calculate proper font size int pt = 0; FontMetrics fm; do { pt++;
  292.              * Font font = new Font(qLabel.getFont().getName(), Font.PLAIN, pt);
  293.              * fm = qLabel.getFontMetrics(font); fm.stringWidth(text); } while
  294.              * (fm.stringWidth(text) < qLabel.getWidth()); pt--;
  295.              */
  296.  
  297.             // qLabel.setSize(qLabel.getWidth(), fm.getHeight());
  298.             // qLabel.setLocation(0, (height - fm.getHeight()) / 2);
  299.             qLabel.setFont(new Font(qLabel.getFont().getName(), Font.PLAIN, pt));
  300.             qLabel.setText("<html><center><p style=\"width:" + width + "\">" + text + "</p></center></html>");
  301.             qLabel.setSize(qLabel.getPreferredSize());
  302.             qLabel.setLocation(Math.max((width - qLabel.getWidth()) / 2, 0), (height - qLabel.getHeight()) / 2);
  303.             qLabel.setOpaque(true);
  304.  
  305.             aLabel.setColumns(q.width);
  306.             aLabel.setRows(q.height);
  307.             aLabel.setSize(aLabel.getPreferredSize());
  308.             aLabel.setSize(Math.min(aLabel.getWidth(), width), Math.min(aLabel.getHeight(), height));
  309.             aLabel.setLocation((width - aLabel.getWidth()) / 2, qLabel.getLocation().y + qLabel.getHeight() + 10);
  310.             aLabel.setText("");
  311.  
  312.             frame.setVisible(true);
  313.  
  314.             while (answer == null) {
  315.                 if (toRefresh) {
  316.                     return;
  317.                 }
  318.                 Thread.sleep(100);
  319.             }
  320.  
  321.             q.ans = answer;
  322.             answer = null;
  323.         }
  324.  
  325.         frame.setVisible(false);
  326.  
  327.         if (end) {
  328.             if (notes.size() > 0) {
  329.                 String ret = "";
  330.                 ret += "Notes: \n";
  331.                 for (String note : notes) {
  332.                     ret += note + "\n";
  333.                 }
  334.                 ret += "\n";
  335.                 JOptionPane.showMessageDialog(frame, ret);
  336.                 notes = new ArrayList<String>();           
  337.             }
  338.  
  339.             log.append(t.toString());
  340.             log.flush();
  341.         }
  342.     }
  343.  
  344.     void readConfig(String filename) throws Exception {
  345.         Scanner sc = new Scanner(new File(filename));
  346.         String logFilename = null;
  347.  
  348.         int curLine = 0;
  349.         Task t = null;
  350.         try {
  351.             while (sc.hasNextLine()) {
  352.  
  353.                 curLine++;
  354.  
  355.                 String sLine = sc.nextLine();
  356.                 if (!sLine.contains("=")) {
  357.                     t = null;
  358.                     continue;
  359.                 }
  360.  
  361.                 String[] split = sLine.split("\\=");
  362.  
  363.                 if (split.length != 2) {
  364.                     throw new Exception("There must only be a single equal sign per line");
  365.                 }
  366.  
  367.                 String key = split[0];
  368.                 String val = split[1];
  369.  
  370.                 switch (key) {
  371.                 case "png":
  372.                     imgFilename = val;
  373.                     break;
  374.                 case "icon":
  375.                     iconFilename = val;
  376.                     break;
  377.                 case "logfile":
  378.                     logFilename = val;
  379.                     log = new PrintWriter((new FileOutputStream(new File(val), true)));
  380.                     break;
  381.                 case "bg":
  382.                     String[] nums = val.split(",");
  383.                     if (nums.length < 3 || nums.length > 4) {
  384.                         throw new Exception("You must have 3 to 4 comma separated integers");
  385.                     }
  386.                     int r = Integer.parseInt(nums[0]);
  387.                     int g = Integer.parseInt(nums[1]);
  388.                     int b = Integer.parseInt(nums[2]);
  389.                     if (nums.length == 3)
  390.                         bg = new Color(r, g, b, 255);
  391.                     else
  392.                         bg = new Color(r, g, b, Integer.parseInt(nums[3]));
  393.                     break;
  394.                 case "fg":
  395.                     nums = val.split(",");
  396.                     if (nums.length < 3 || nums.length > 4) {
  397.                         throw new Exception("You must have 3 to 4 comma separated integers");
  398.                     }
  399.                     r = Integer.parseInt(nums[0]);
  400.                     g = Integer.parseInt(nums[1]);
  401.                     b = Integer.parseInt(nums[2]);
  402.                     if (nums.length == 3)
  403.                         fg = new Color(r, g, b, 255);
  404.                     else
  405.                         fg = new Color(r, g, b, Integer.parseInt(nums[3]));
  406.                     break;
  407.                 case "fontpt":
  408.                     pt = Integer.parseInt(val);
  409.                     break;
  410.                 case "start":
  411.                     t = new Task();
  412.                     String[] time = val.split(":");
  413.                     int hours = Integer.parseInt(time[0]);
  414.                     int minutes = Integer.parseInt(time[1]);
  415.                     t.start = hours * 60 + minutes;
  416.                     tasks.add(t);
  417.                     break;
  418.                 case "finish":
  419.                     if (t == null) {
  420.                         throw new Exception("\'finish\' was parsed before corresponding \'start\'");
  421.                     }
  422.                     time = val.split(":");
  423.                     hours = Integer.parseInt(time[0]);
  424.                     minutes = Integer.parseInt(time[1]);
  425.                     t.end = hours * 60 + minutes;
  426.                     break;
  427.                 default:
  428.                     String[] dim = key.split("x");
  429.                     if (dim.length != 2) {
  430.                         throw new Exception("Unknown key: " + key);
  431.                     }
  432.                     if (t == null) {
  433.                         throw new Exception("A question was parsed before a corresponding \'start\' was found.");
  434.                     }
  435.                     int w = Integer.parseInt(dim[0]);
  436.                     int h = Integer.parseInt(dim[1]);
  437.  
  438.                     if (t.end == -1)
  439.                         t.addQuestion(val, w, h, true);
  440.                     else
  441.                         t.addQuestion(val, w, h, false);
  442.                 }
  443.             }
  444.             curLine = -1;
  445.             curTaskID = 0;
  446.             Scanner logFile = new Scanner(new File(logFilename));
  447.             logFile.useDelimiter("\\Z");
  448.             if( logFile.hasNext() )
  449.             {
  450.                 String content = logFile.next();
  451.                 String[] lines = content.split("\n");
  452.                 for (int i = lines.length - 1; i >= 0; i--) {
  453.                     String line = lines[i];
  454.                     if (line.contains("Task")) {
  455.                         curTaskID = new Scanner(line.split("#")[1]).nextInt();
  456.                         break;
  457.                     }
  458.                 }
  459.             }
  460.             logFile.close();
  461.         } catch (Exception e) {
  462.             e.printStackTrace();
  463.             if (curLine != -1)
  464.                 throw new Exception("Line: " + curLine + "\n" + e.getMessage(), e);
  465.             else
  466.                 throw new Exception(e.getMessage(), e);
  467.         } finally {
  468.             if (sc != null)
  469.                 sc.close();
  470.         }
  471.  
  472.     }
  473.  
  474.     class Question {
  475.         public String ans;
  476.         public String text;
  477.         public int width;
  478.         public int height;
  479.         public boolean pre;
  480.  
  481.         Question(String text, int width, int height, boolean pre) {
  482.             this.text = text;
  483.             this.width = width;
  484.             this.height = height;
  485.             this.pre = pre;
  486.         }
  487.     }
  488.  
  489.     class Task {
  490.  
  491.         private int ID;
  492.  
  493.         public ArrayList<Question> questions = new ArrayList<Question>();
  494.  
  495.         public int start = -1;
  496.         public int end = -1;
  497.  
  498.         public Task() {
  499.             curTaskID++;
  500.             ID = curTaskID;
  501.         }
  502.  
  503.         void addQuestion(String q, int width, int height, boolean pre) {
  504.             Question question = new Question(q, width, height, pre);
  505.             questions.add(question);
  506.         }
  507.  
  508.         public String toString() {
  509.             String ret = "Task #" + ID + " ["
  510.                     + DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.US).format(new Date()) + " " + getTime(start)
  511.                     + " - " + getTime(end) + "]\n\n";
  512.  
  513. //          if (notes != null && notes.size() > 0) {
  514. //              ret += "Notes: \n";
  515. //              for (String note : notes) {
  516. //                  ret += note + "\n";
  517. //              }
  518. //              ret += "\n";
  519. //          }
  520.  
  521.             int qn = 0;
  522.             for (Question q : questions) {
  523.                 qn++;
  524.                 ret += "Question #" + qn + "\n";
  525.                 ret += q.text + ": " + q.ans + "\n\n";
  526.             }
  527.             ret += "\n";
  528.             return ret;
  529.         }
  530.     }
  531.  
  532.     class ImagePanel extends JComponent {
  533.         private static final long serialVersionUID = 4522060807412287578L;
  534.         private Image image;
  535.  
  536.         public ImagePanel(Image image) {
  537.             this.image = image;
  538.         }
  539.  
  540.         @Override
  541.         protected void paintComponent(Graphics g) {
  542.             super.paintComponent(g);
  543.             g.drawImage(image, 0, 0, this);
  544.         }
  545.     }
  546.  
  547.     public static void main(String[] args) throws IOException {
  548.  
  549.         try {
  550.             Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
  551.             logger.setLevel(Level.OFF);
  552.             GlobalScreen.registerNativeHook();
  553.         } catch (NativeHookException e1) {
  554.             e1.printStackTrace();
  555.             return;
  556.         }
  557.  
  558.         Main c = new Main();
  559.         GlobalScreen.addNativeKeyListener(c);
  560.         toRefresh = true;
  561.         while (toRefresh) {
  562.             toRefresh = false;
  563.             try {
  564.                 c.run(args);
  565.             } catch (InterruptedException e) {
  566.                 e.printStackTrace();
  567.             }
  568.         }
  569.        
  570.         System.exit(1);
  571.     }
  572.  
  573.     int clicks = 0;
  574.  
  575.     @Override
  576.     public void mouseClicked(MouseEvent arg0) {
  577.         clicks++;
  578.         if (clicks > 20) {
  579.  
  580.         }
  581.     }
  582.  
  583.     @Override
  584.     public void mouseEntered(MouseEvent arg0) {
  585.  
  586.     }
  587.  
  588.     @Override
  589.     public void mouseExited(MouseEvent arg0) {
  590.  
  591.     }
  592.  
  593.     @Override
  594.     public void mousePressed(MouseEvent arg0) {
  595.  
  596.     }
  597.  
  598.     @Override
  599.     public void mouseReleased(MouseEvent arg0) {
  600.  
  601.     }
  602.  
  603.     static boolean toRefresh;
  604.  
  605.     @Override
  606.     public void actionPerformed(ActionEvent ae) {
  607.         switch (ae.getActionCommand()) {
  608.         case "Exit":
  609.             System.exit(0);
  610.             break;
  611.         case "Refresh":
  612.             toRefresh = true;
  613.             break;
  614.         }
  615.     }
  616.  
  617.     @Override
  618.     public void nativeKeyPressed(NativeKeyEvent e) {
  619.         pressedKeys.add(e.getKeyCode());
  620.     }
  621.  
  622.     @Override
  623.     public void nativeKeyReleased(NativeKeyEvent e) {
  624.         pressedKeys.remove(e.getKeyCode());
  625.     }
  626.    
  627.     @Override
  628.     public void nativeKeyTyped(NativeKeyEvent e) {
  629.         if (e.getKeyChar() == 'I' && (pressedKeys.contains(NativeKeyEvent.VC_CONTROL_L)
  630.                 || pressedKeys.contains(NativeKeyEvent.VC_CONTROL_R))) {
  631.  
  632.             String s = JOptionPane.showInputDialog(frame, null);
  633.            
  634.             // If a string was returned, save the note
  635.             if ((s != null) && (s.length() > 0)) {
  636.                 notes.add(s);
  637.             }
  638.         }  
  639.     }
  640.  
  641.     String getTime(int time) {
  642.         return ((time / 60) < 10 ? "0" : "") + (time / 60) + ":" + ((time % 60) < 10 ? "0" : "") + (time % 60);
  643.     }
  644. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement