Jelajahi Sumber

TrayIcon, proper directory structure and bugfix

Added a system tray icon to allow the program to run in the background.
Also fixed the directory structure to follow Maven standards.

Fixed a bug that allowed null speed profiles to be added.
Tankernn 8 tahun lalu
induk
melakukan
2547220949

+ 36 - 13
pom.xml

@@ -1,10 +1,10 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
-	<groupId>eu.tankernn.camsucks</groupId>
-	<artifactId>CamSucks</artifactId>
-	<version>0.0.1</version>
-	<name>CAM Sucks</name>
+	<groupId>eu.tankernn.grid</groupId>
+	<artifactId>java-grid-control</artifactId>
+	<version>1.0.0</version>
+	<name>JavaGridControl</name>
 	<description>An alternative app for controlling the NZXT GRID+.</description>
 
 	<dependencies>
@@ -23,16 +23,35 @@
 	</dependencies>
 
 	<build>
-		<sourceDirectory>src</sourceDirectory>
-		<resources>
-			<resource>
-				<directory>src</directory>
-				<excludes>
-					<exclude>**/*.java</exclude>
-				</excludes>
-			</resource>
-		</resources>
+		<finalName>${project.artifactId}-${project.version}.${build.number}</finalName>
 		<plugins>
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+						<configuration>
+							<archive>
+								<manifest>
+									<addClasspath>true</addClasspath>
+									<mainClass>eu.tankernn.grid.GridControl</mainClass>
+								</manifest>
+							</archive>
+							<!-- The filename of the assembled distribution file defualt ${project.build.finalName} -->
+							<finalName>${project.build.finalName}</finalName>
+							<appendAssemblyId>false</appendAssemblyId>
+						</configuration>
+					</execution>
+				</executions>
+				<configuration>
+					<descriptorRefs>
+						<descriptorRef>jar-with-dependencies</descriptorRef>
+					</descriptorRefs>
+				</configuration>
+			</plugin>
 			<plugin>
 				<artifactId>maven-compiler-plugin</artifactId>
 				<version>3.6.1</version>
@@ -43,4 +62,8 @@
 			</plugin>
 		</plugins>
 	</build>
+	
+	<properties>
+		<build.number>SNAPSHOT</build.number>
+	</properties>
 </project>

+ 0 - 0
src/eu/tankernn/grid/Fan.java → src/main/java/eu/tankernn/grid/Fan.java


+ 0 - 0
src/eu/tankernn/grid/FanSpeedProfile.java → src/main/java/eu/tankernn/grid/FanSpeedProfile.java


+ 63 - 56
src/eu/tankernn/grid/GridControl.java → src/main/java/eu/tankernn/grid/GridControl.java

@@ -1,7 +1,11 @@
 package eu.tankernn.grid;
 
-import java.awt.event.WindowEvent;
-import java.awt.event.WindowListener;
+import java.awt.AWTException;
+import java.awt.Image;
+import java.awt.MenuItem;
+import java.awt.PopupMenu;
+import java.awt.SystemTray;
+import java.awt.TrayIcon;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.FileWriter;
@@ -10,6 +14,7 @@ import java.io.Reader;
 import java.io.Writer;
 import java.util.Arrays;
 
+import javax.imageio.ImageIO;
 import javax.swing.JFrame;
 
 import com.google.gson.Gson;
@@ -18,42 +23,78 @@ import com.google.gson.GsonBuilder;
 import eu.tankernn.grid.frame.GridControlPanel;
 import eu.tankernn.grid.model.ComputerModel;
 
-public class GridControl implements WindowListener, Runnable {
+public class GridControl implements Runnable {
 
 	private static final String PROFILE_PATH = "profiles.json";
 	private static final String SETTINGS_PATH = "settings.json";
 
-	private Thread t;
+	private Thread t = new Thread(this, "Polling thread");
 
 	private int pollingSpeed = 500;
 
 	private ComputerModel model = new ComputerModel();
 
 	private GridControlPanel frame;
+	private TrayIcon trayIcon;
 
 	public GridControl(boolean gui) {
 		readSettings();
-		
+
 		if (gui) {
+			Image image;
+			try {
+				image = ImageIO.read(ClassLoader.class.getResourceAsStream("/JGC.png"));
+			} catch (IOException e) {
+				e.printStackTrace();
+				return;
+			}
 			frame = new GridControlPanel(this, model);
 			frame.setResizable(true);
+			frame.setIconImage(image);
 			frame.pack();
-			frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
-			frame.addWindowListener(this);
+			frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
 			frame.setVisible(true);
+			addTrayIcon(image);
 		}
 
-		t = new Thread(this);
-		t.setDaemon(true);
 		t.start();
 	}
-	
+
+	private void addTrayIcon(Image image) {
+		// Check the SystemTray is supported
+		if (!SystemTray.isSupported()) {
+			System.out.println("SystemTray is not supported");
+			return;
+		}
+		final PopupMenu popup = new PopupMenu();
+
+		// Create a pop-up menu components
+		MenuItem openItem = new MenuItem("Open");
+		openItem.addActionListener(a -> frame.setVisible(true));
+		MenuItem exitItem = new MenuItem("Exit");
+		exitItem.addActionListener(a -> this.exit());
+
+		// Add components to pop-up menu
+		popup.add(openItem);
+		popup.addSeparator();
+		popup.add(exitItem);
+
+		trayIcon = new TrayIcon(image, "JavaGridControl", popup);
+		trayIcon.setImageAutoSize(true);
+
+		try {
+			SystemTray.getSystemTray().add(trayIcon);
+		} catch (AWTException e) {
+			System.out.println("TrayIcon could not be added.");
+		}
+	}
+
 	public void readSettings() {
 		Gson gson = new GsonBuilder().create();
 		try (Reader reader = new FileReader(PROFILE_PATH)) {
 			Arrays.stream(gson.fromJson(reader, FanSpeedProfile[].class)).forEach(model::addProfile);
 		} catch (FileNotFoundException e) {
-			e.printStackTrace();
+			// Not a problem
 		} catch (IOException e) {
 			e.printStackTrace();
 		}
@@ -65,7 +106,9 @@ public class GridControl implements WindowListener, Runnable {
 			pollingSpeed = settings.pollingRate;
 			model.setMinSpeed(settings.minSpeed);
 		} catch (FileNotFoundException e) {
-			e.printStackTrace();
+			System.out.println("No config file found, using default settings.");
+			for (int i = 0; i < 6; i++)
+				model.getGrid().getFan(i).setProfile(model.getProfiles().get(0));
 		} catch (IOException e) {
 			e.printStackTrace();
 		}
@@ -81,9 +124,7 @@ public class GridControl implements WindowListener, Runnable {
 		}
 		// Save misc. settings
 		try (Writer writer = new FileWriter(SETTINGS_PATH)) {
-			gson.toJson(new Settings(model.getGrid().getCommunicator().getPortName(),
-					model.getGrid().fanStream().map(f -> f.getProfile().name).toArray(String[]::new), pollingSpeed,
-					model.getMinSpeed()), writer);
+			gson.toJson(new Settings(model.getGrid().getCommunicator().getPortName(), model.getGrid().fanStream().map(f -> f.getProfile().name).toArray(String[]::new), pollingSpeed, model.getMinSpeed()), writer);
 		} catch (IOException e) {
 			e.printStackTrace();
 		}
@@ -110,55 +151,21 @@ public class GridControl implements WindowListener, Runnable {
 
 	/**
 	 * 
-	 * @param args
-	 *            the command line arguments
+	 * @param args the command line arguments
 	 */
 	public static void main(String[] args) {
 		new GridControl(!Arrays.asList(args).contains("nogui"));
 	}
 
-	@Override
-	public void windowOpened(WindowEvent e) {
-		// TODO Auto-generated method stub
-
-	}
-
-	@Override
-	public void windowClosing(WindowEvent e) {
+	public void exit() {
 		t.interrupt();
 		model.getGrid().disconnect();
 		saveSettings();
-		e.getWindow().dispose();
-	}
-
-	@Override
-	public void windowClosed(WindowEvent e) {
-		// TODO Auto-generated method stub
-
-	}
-
-	@Override
-	public void windowIconified(WindowEvent e) {
-		// TODO Auto-generated method stub
-
-	}
-
-	@Override
-	public void windowDeiconified(WindowEvent e) {
-		// TODO Auto-generated method stub
-
-	}
-
-	@Override
-	public void windowActivated(WindowEvent e) {
-		// TODO Auto-generated method stub
-
-	}
-
-	@Override
-	public void windowDeactivated(WindowEvent e) {
-		// TODO Auto-generated method stub
-
+		frame.dispose();
+		SystemTray.getSystemTray().remove(trayIcon);
+		for (Thread t : Thread.getAllStackTraces().keySet())
+			if (t.isAlive())
+				System.out.println(t);
 	}
 
 	public void setPollingSpeed(int value) {

+ 0 - 0
src/eu/tankernn/grid/Settings.java → src/main/java/eu/tankernn/grid/Settings.java


+ 0 - 0
src/eu/tankernn/grid/frame/FanPanel.java → src/main/java/eu/tankernn/grid/frame/FanPanel.java


+ 24 - 19
src/eu/tankernn/grid/frame/GridControlPanel.java → src/main/java/eu/tankernn/grid/frame/GridControlPanel.java

@@ -33,15 +33,19 @@ public class GridControlPanel extends JFrame {
 	private static final long serialVersionUID = 1L;
 
 	private ComputerModel model;
-	
+
 	private JMenuBar menuBar = new JMenuBar();
-	private JMenu fileMenu = new JMenu("File"), profileMenu = new JMenu("Profiles");
-	private JMenuItem saveSettings = new JMenuItem("Save settings..."), addProfile = new JMenuItem("Add profile...");
-	
+	private JMenu fileMenu = new JMenu("File"),
+			profileMenu = new JMenu("Profiles");
+	private JMenuItem saveSettings = new JMenuItem("Save settings..."),
+			addProfile = new JMenuItem("Add profile...");
+
 	private FanPanel[] fanPanels;
-	private JPanel serialPanel = new JPanel(), gridPanel = new JPanel(), infoPanel = new JPanel();
+	private JPanel serialPanel = new JPanel(), gridPanel = new JPanel(),
+			infoPanel = new JPanel();
 
-	private JSpinner minSpeed = new JSpinner(new SpinnerNumberModel(30, 0, 100, 5)), pollingSpeed = new JSpinner(new SpinnerNumberModel(500, 100, 2000, 100));
+	private JSpinner minSpeed = new JSpinner(new SpinnerNumberModel(30, 0, 100, 5)),
+			pollingSpeed = new JSpinner(new SpinnerNumberModel(500, 100, 2000, 100));
 
 	private JComboBox<String> portMap = new JComboBox<>();
 
@@ -70,7 +74,7 @@ public class GridControlPanel extends JFrame {
 	public GridControlPanel(GridControl control, ComputerModel model) {
 		setModel(model);
 		this.setLayout(new BorderLayout());
-		
+
 		menuBar.add(fileMenu);
 		fileMenu.add(saveSettings);
 		saveSettings.addActionListener(e -> control.saveSettings());
@@ -78,18 +82,19 @@ public class GridControlPanel extends JFrame {
 		profileMenu.add(addProfile);
 		addProfile.addActionListener(e -> {
 			FanSpeedProfile p = new ProfileEditor().editProfile(null);
-			model.addProfile(p);
-			Arrays.stream(fanPanels).forEach(f -> f.addProfile(p));
+			if (p != null) {
+				model.addProfile(p);
+				Arrays.stream(fanPanels).forEach(f -> f.addProfile(p));
+			}
 		});
-		
+
 		this.setJMenuBar(this.menuBar);
-		
+
 		serialPanel.setLayout(new FlowLayout());
 		serialPanel.setBorder(new TitledBorder("Serial settings"));
 		serialPanel.add(labelledComponent("COM port: ", portMap));
 		serialPanel.add(labelledComponent("Polling speed: ", pollingSpeed));
 		this.add(serialPanel, BorderLayout.NORTH);
-		
 
 		fanPanels = model.getGrid().fanStream().map(f -> new FanPanel(f, model.getProfiles())).toArray(FanPanel[]::new);
 
@@ -98,15 +103,15 @@ public class GridControlPanel extends JFrame {
 			gridPanel.add(p);
 
 		this.add(gridPanel, BorderLayout.CENTER);
-		
+
 		minSpeed.setValue(model.getMinSpeed());
 		minSpeed.addChangeListener(this::setMinRPM);
-		
+
 		pollingSpeed.setValue(control.getPollingSpeed());
 		pollingSpeed.addChangeListener(e -> {
 			control.setPollingSpeed((int) pollingSpeed.getValue());
 		});
-		
+
 		infoPanel.setBorder(new TitledBorder("System info"));
 		infoPanel.setLayout(new GridLayout(3, 2));
 		infoPanel.add(CPULabel);
@@ -116,17 +121,17 @@ public class GridControlPanel extends JFrame {
 		infoPanel.add(PowerLabel);
 		infoPanel.add(labelledComponent("Minimum speed (%): ", minSpeed));
 		this.add(infoPanel, BorderLayout.SOUTH);
-		
+
 		portMap.addItemListener(new ItemListener() {
 			@Override
 			public void itemStateChanged(ItemEvent e) {
 				setPort(e);
 			}
 		});
-		
+
 		this.setTitle("JavaGridControl");
 	}
-	
+
 	private JPanel labelledComponent(String labelText, JComponent component) {
 		JPanel panel = new JPanel(new FlowLayout());
 		panel.add(new JLabel(labelText));
@@ -148,7 +153,7 @@ public class GridControlPanel extends JFrame {
 		for (String key : model.getPortMap().keySet()) {
 			portMap.addItem(key);
 		}
-		
+
 		setPort(null);
 	}
 

+ 61 - 61
src/eu/tankernn/grid/frame/ProfileEditor.java → src/main/java/eu/tankernn/grid/frame/ProfileEditor.java

@@ -1,61 +1,61 @@
-package eu.tankernn.grid.frame;
-
-import java.awt.BorderLayout;
-import java.awt.GridLayout;
-import java.util.Arrays;
-import java.util.stream.IntStream;
-
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JSlider;
-import javax.swing.JTextField;
-
-import eu.tankernn.grid.FanSpeedProfile;
-
-public class ProfileEditor {
-
-	public FanSpeedProfile editProfile(FanSpeedProfile profile) {
-		JPanel panel = new JPanel(), sliderPanel = new JPanel();
-		JSlider[] sliders;
-		JTextField nameField = new JTextField();
-		if (profile != null) {
-			nameField.setText(profile.name);
-			sliders = Arrays.stream(profile.percentages).mapToObj(i -> new JSlider(JSlider.VERTICAL, 0, 100, i)).toArray(JSlider[]::new);
-		} else {
-			sliders = IntStream.range(0, FanSpeedProfile.STEPS).mapToObj(i -> new JSlider(JSlider.VERTICAL)).toArray(JSlider[]::new);
-		}
-		
-		for (JSlider s : sliders) {
-			s.setSnapToTicks(true);
-			s.setMinorTickSpacing(5);
-		}
-		
-		panel.setLayout(new BorderLayout());
-		panel.add(new JLabel("Profile name: "));
-		panel.add(nameField, BorderLayout.NORTH);
-		
-		sliderPanel.setLayout(new GridLayout(1, sliders.length));
-		for (JSlider s : sliders)
-			sliderPanel.add(s);
-		panel.add(sliderPanel, BorderLayout.CENTER);
-		
-
-		int response = JOptionPane.showConfirmDialog(null, panel, "Fan Speed Profile Editor", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
-
-		if (response == JOptionPane.OK_OPTION) {
-			FanSpeedProfile newProfile = new FanSpeedProfile(nameField.getText(), Arrays.stream(sliders).mapToInt(JSlider::getValue).toArray());
-			if (nameField.getText().isEmpty()) {
-				JOptionPane.showMessageDialog(null, "Please enter a name for the profile.");
-				return editProfile(newProfile);
-			}
-			return newProfile;
-		} else {
-			return profile;
-		}
-	}
-	
-	public static void main(String[] args) {
-		System.out.println(new ProfileEditor().editProfile(null));
-	}
-}
+package eu.tankernn.grid.frame;
+
+import java.awt.BorderLayout;
+import java.awt.GridLayout;
+import java.util.Arrays;
+import java.util.stream.IntStream;
+
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+
+import eu.tankernn.grid.FanSpeedProfile;
+
+public class ProfileEditor {
+
+	public FanSpeedProfile editProfile(FanSpeedProfile profile) {
+		JPanel panel = new JPanel(), sliderPanel = new JPanel();
+		JSlider[] sliders;
+		JTextField nameField = new JTextField();
+		if (profile != null) {
+			nameField.setText(profile.name);
+			sliders = Arrays.stream(profile.percentages).mapToObj(i -> new JSlider(JSlider.VERTICAL, 0, 100, i)).toArray(JSlider[]::new);
+		} else {
+			sliders = IntStream.range(0, FanSpeedProfile.STEPS).mapToObj(i -> new JSlider(JSlider.VERTICAL)).toArray(JSlider[]::new);
+		}
+		
+		for (JSlider s : sliders) {
+			s.setSnapToTicks(true);
+			s.setMinorTickSpacing(5);
+		}
+		
+		panel.setLayout(new BorderLayout());
+		panel.add(new JLabel("Profile name: "));
+		panel.add(nameField, BorderLayout.NORTH);
+		
+		sliderPanel.setLayout(new GridLayout(1, sliders.length));
+		for (JSlider s : sliders)
+			sliderPanel.add(s);
+		panel.add(sliderPanel, BorderLayout.CENTER);
+		
+
+		int response = JOptionPane.showConfirmDialog(null, panel, "Fan Speed Profile Editor", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
+
+		if (response == JOptionPane.OK_OPTION) {
+			FanSpeedProfile newProfile = new FanSpeedProfile(nameField.getText(), Arrays.stream(sliders).mapToInt(JSlider::getValue).toArray());
+			if (nameField.getText().isEmpty()) {
+				JOptionPane.showMessageDialog(null, "Please enter a name for the profile.");
+				return editProfile(newProfile);
+			}
+			return newProfile;
+		} else {
+			return profile;
+		}
+	}
+	
+	public static void main(String[] args) {
+		System.out.println(new ProfileEditor().editProfile(null));
+	}
+}

+ 0 - 0
src/eu/tankernn/grid/model/Communicator.java → src/main/java/eu/tankernn/grid/model/Communicator.java


+ 0 - 0
src/eu/tankernn/grid/model/ComputerModel.java → src/main/java/eu/tankernn/grid/model/ComputerModel.java


+ 0 - 0
src/eu/tankernn/grid/model/GRID.java → src/main/java/eu/tankernn/grid/model/GRID.java


+ 0 - 0
src/eu/tankernn/grid/model/Sensor.java → src/main/java/eu/tankernn/grid/model/Sensor.java


+ 0 - 0
src/eu/tankernn/grid/model/jWMI.java → src/main/java/eu/tankernn/grid/model/jWMI.java


TEMPAT SAMPAH
src/main/resources/JGC.png