Ref: cleanup, organise packages
This commit is contained in:
63
src/main/java/com/sheepit/client/ui/Gui.java
Normal file
63
src/main/java/com/sheepit/client/ui/Gui.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2013 Laurent CLOUET
|
||||
* Author Laurent CLOUET <laurent.clouet@nopnop.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui;
|
||||
|
||||
import com.sheepit.client.Client;
|
||||
import com.sheepit.client.network.DownloadProgress;
|
||||
|
||||
public interface Gui {
|
||||
public void start();
|
||||
|
||||
public void stop();
|
||||
|
||||
public void status(String msg_);
|
||||
|
||||
public void status(String msg_, boolean overwriteSuspendedMsg);
|
||||
|
||||
public void status(String msg_, int progress);
|
||||
|
||||
public void updateTrayIcon(Integer percentage_);
|
||||
|
||||
public void setRenderingProjectName(String name_);
|
||||
|
||||
public void setRemainingTime(String time_);
|
||||
|
||||
public void setRenderingTime(String time_);
|
||||
|
||||
public void displayTransferStats(TransferStats downloads, TransferStats uploads);
|
||||
|
||||
public void displayStats(Stats stats);
|
||||
|
||||
public void displayUploadQueueStats(int queueSize, long queueVolume);
|
||||
|
||||
public void error(String err_);
|
||||
|
||||
public void AddFrameRendered();
|
||||
|
||||
public void successfulAuthenticationEvent(String publickey);
|
||||
|
||||
public void setClient(Client cli);
|
||||
|
||||
public void setComputeMethod(String computeMethod_);
|
||||
|
||||
public Client getClient();
|
||||
|
||||
public DownloadProgress getDownloadProgress();
|
||||
}
|
||||
496
src/main/java/com/sheepit/client/ui/GuiSwing.java
Normal file
496
src/main/java/com/sheepit/client/ui/GuiSwing.java
Normal file
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 Laurent CLOUET
|
||||
* Author Laurent CLOUET <laurent.clouet@nopnop.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui;
|
||||
|
||||
import com.formdev.flatlaf.FlatDarkLaf;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.sheepit.client.Client;
|
||||
import com.sheepit.client.config.Configuration;
|
||||
import com.sheepit.client.network.DownloadProgress;
|
||||
import com.sheepit.client.logger.Log;
|
||||
import com.sheepit.client.config.SettingsLoader;
|
||||
import com.sheepit.client.ui.swing.activity.Settings;
|
||||
import com.sheepit.client.ui.swing.activity.Working;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Image;
|
||||
import java.awt.MenuItem;
|
||||
import java.awt.PopupMenu;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.TrayIcon;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowStateListener;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class GuiSwing extends JFrame implements Gui {
|
||||
public static final String type = "swing";
|
||||
private static final String logoPath = "/sheepit-logo.png";
|
||||
public static final int WIDTH = 540;
|
||||
|
||||
public static void drawVersionStringOnImage(final BufferedImage image, String versionString) {
|
||||
var watermarkWidth = image.getWidth();
|
||||
var watermarkHeight = image.getHeight();
|
||||
|
||||
Graphics2D gph = (Graphics2D) image.getGraphics();
|
||||
// use anti aliasing to smooth version string
|
||||
gph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
gph.setFont(gph.getFont().deriveFont(12f));
|
||||
|
||||
FontMetrics fontMetrics = gph.getFontMetrics();
|
||||
// move text to the very right of the image respecting its length
|
||||
int x = watermarkWidth - fontMetrics.stringWidth(versionString);
|
||||
// the bottom of the image, but give enough headroom for descending letters like g
|
||||
int y = watermarkHeight - fontMetrics.getMaxDescent();
|
||||
|
||||
gph.drawString(versionString, x, y);
|
||||
gph.dispose();
|
||||
}
|
||||
|
||||
@NotNull public static JLabel createLogoWithWatermark() {
|
||||
final URL logoURL = GuiSwing.class.getResource(logoPath);
|
||||
|
||||
// If logo cannot be found, return dummy image
|
||||
if (logoURL == null) {
|
||||
System.err.println("Error: Unable to find logo " + logoPath);
|
||||
return new JLabel();
|
||||
}
|
||||
|
||||
JLabel labelImage;
|
||||
try {
|
||||
// Include the version of the app as a watermark in the SheepIt logo.
|
||||
final BufferedImage watermark = ImageIO.read(logoURL);
|
||||
String versionString = "v" + Configuration.jarVersion;
|
||||
drawVersionStringOnImage(watermark, versionString);
|
||||
|
||||
labelImage = new JLabel(new ImageIcon(watermark));
|
||||
}
|
||||
catch (Exception e) {
|
||||
// If something fails, we just show the SheepIt logo (without any watermark)
|
||||
ImageIcon image = new ImageIcon(logoURL);
|
||||
labelImage = new JLabel(image);
|
||||
}
|
||||
return labelImage;
|
||||
}
|
||||
|
||||
public enum ActivityType {
|
||||
WORKING, SETTINGS
|
||||
}
|
||||
|
||||
private SystemTray sysTray;
|
||||
private JPanel panel;
|
||||
private Working activityWorking;
|
||||
private Settings activitySettings;
|
||||
private TrayIcon trayIcon;
|
||||
private boolean useSysTray;
|
||||
private String title;
|
||||
|
||||
private int framesRendered;
|
||||
|
||||
private boolean waitingForAuthentication;
|
||||
private Client client;
|
||||
private DownloadProgress downloadProgress;
|
||||
|
||||
private BufferedImage iconSprites;
|
||||
|
||||
@Getter @Setter private SettingsLoader settingsLoader;
|
||||
|
||||
private ThreadClient threadClient;
|
||||
|
||||
public GuiSwing(boolean useSysTray_, String title_) {
|
||||
downloadProgress = new DownloadProgress(this);
|
||||
framesRendered = 0;
|
||||
useSysTray = useSysTray_;
|
||||
title = title_;
|
||||
waitingForAuthentication = true;
|
||||
|
||||
new Timer().scheduleAtFixedRate(new TimerTask() {
|
||||
@Override public void run() {
|
||||
if (activityWorking != null) {
|
||||
activityWorking.updateTime();
|
||||
}
|
||||
}
|
||||
}, 2 * 1000, 2 * 1000);
|
||||
}
|
||||
|
||||
@Override public void start() {
|
||||
if (useSysTray) {
|
||||
try {
|
||||
sysTray = SystemTray.getSystemTray();
|
||||
if (SystemTray.isSupported()) {
|
||||
addWindowStateListener(new WindowStateListener() {
|
||||
@Override public void windowStateChanged(WindowEvent e) {
|
||||
if (e.getNewState() == ICONIFIED) {
|
||||
hideToTray();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (UnsupportedOperationException e) {
|
||||
sysTray = null;
|
||||
}
|
||||
}
|
||||
|
||||
// load the images sprite and split into individual images
|
||||
URL spriteSequenceUrl = getClass().getResource("/icon-sprites.png");
|
||||
|
||||
if (spriteSequenceUrl != null) {
|
||||
try {
|
||||
iconSprites = ImageIO.read(spriteSequenceUrl);
|
||||
|
||||
setIconImage(extractImageFromSprite(-1)); // sprite 0 is standard Sheep It! icon
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
setTitle(title);
|
||||
setSize(WIDTH, 760);
|
||||
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
|
||||
panel = new JPanel();
|
||||
panel.setLayout(new GridBagLayout());
|
||||
Dimension panelPrefSize = new Dimension(this.getSize().width - 20, this.getSize().height);
|
||||
panel.setPreferredSize(panelPrefSize);
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(panel);
|
||||
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
|
||||
//adjust scrollbar thickness
|
||||
scrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(13, 0));
|
||||
scrollPane.getHorizontalScrollBar().setPreferredSize(new Dimension(0, 13));
|
||||
|
||||
//adjust the speed of scrolling
|
||||
scrollPane.getVerticalScrollBar().setUnitIncrement(50);
|
||||
scrollPane.getHorizontalScrollBar().setUnitIncrement(50);
|
||||
|
||||
setContentPane(scrollPane);
|
||||
panel.setBorder(new EmptyBorder(20, 20, 20, 20));
|
||||
|
||||
activityWorking = new Working(this);
|
||||
activitySettings = new Settings(this);
|
||||
|
||||
this.showActivity(ActivityType.SETTINGS);
|
||||
|
||||
try {
|
||||
if ("light".equals(client.getConfiguration().getTheme())) {
|
||||
UIManager.setLookAndFeel(new FlatLightLaf());
|
||||
}
|
||||
else if ("dark".equals(client.getConfiguration().getTheme())) {
|
||||
UIManager.setLookAndFeel(new FlatDarkLaf());
|
||||
}
|
||||
|
||||
// Apply the selected theme to swing components
|
||||
SwingUtilities.invokeAndWait(() -> FlatLaf.updateUI());
|
||||
}
|
||||
catch (UnsupportedLookAndFeelException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
while (waitingForAuthentication) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
wait();
|
||||
}
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void stop() {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@Override public void status(String msg_) {
|
||||
status(msg_, false);
|
||||
}
|
||||
|
||||
@Override public void status(String msg_, boolean overwriteSuspendedMsg) {
|
||||
if (activityWorking != null) {
|
||||
this.activityWorking.setStatus(msg_, overwriteSuspendedMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void status(String msg, int progress) {
|
||||
if (activityWorking != null) {
|
||||
this.activityWorking.setStatus(String.format("%s %d%%", msg, progress));
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setRenderingProjectName(String name_) {
|
||||
if (activityWorking != null) {
|
||||
this.activityWorking.setRenderingProjectName(name_);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void error(String msg_) {
|
||||
status(msg_, true);
|
||||
}
|
||||
|
||||
@Override public void setRemainingTime(String time_) {
|
||||
if (activityWorking != null) {
|
||||
this.activityWorking.setRemainingTime(time_);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setRenderingTime(String time_) {
|
||||
if (activityWorking != null) {
|
||||
this.activityWorking.setRenderingTime(time_);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public synchronized void displayTransferStats(TransferStats downloads, TransferStats uploads) {
|
||||
this.activityWorking.displayTransferStats(downloads, uploads);
|
||||
}
|
||||
|
||||
@Override public void AddFrameRendered() {
|
||||
framesRendered++;
|
||||
|
||||
if (activityWorking != null) {
|
||||
this.activityWorking.setRenderedFrame(framesRendered);
|
||||
}
|
||||
else {
|
||||
Log.getInstance().error("GuiSwing::AddFrameRendered() error: no working activity");
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void displayStats(Stats stats) {
|
||||
if (activityWorking != null) {
|
||||
this.activityWorking.displayStats(stats);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void displayUploadQueueStats(int queueSize, long queueVolume) {
|
||||
if (activityWorking != null) {
|
||||
this.activityWorking.displayUploadQueueStats(queueSize, queueVolume);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Client getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override public DownloadProgress getDownloadProgress() {
|
||||
return downloadProgress;
|
||||
}
|
||||
|
||||
@Override public void setClient(Client cli) {
|
||||
client = cli;
|
||||
}
|
||||
|
||||
@Override public void setComputeMethod(String computeMethod) {
|
||||
this.activityWorking.setComputeMethod(computeMethod);
|
||||
}
|
||||
|
||||
public Configuration getConfiguration() {
|
||||
return client.getConfiguration();
|
||||
}
|
||||
|
||||
@Override public void successfulAuthenticationEvent(String publickey) {
|
||||
if (settingsLoader != null) {
|
||||
if (publickey != null && settingsLoader.getLogin().isLaunchCommand() == false) {
|
||||
settingsLoader.getPassword().setValue(publickey);
|
||||
}
|
||||
settingsLoader.saveFile();
|
||||
}
|
||||
}
|
||||
|
||||
public void setCredentials(String contentLogin, String contentPassword) {
|
||||
client.getConfiguration().setLogin(contentLogin);
|
||||
client.getConfiguration().setPassword(contentPassword);
|
||||
|
||||
waitingForAuthentication = false;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
if (threadClient == null || threadClient.isAlive() == false) {
|
||||
threadClient = new ThreadClient();
|
||||
threadClient.start();
|
||||
}
|
||||
|
||||
showActivity(ActivityType.WORKING);
|
||||
}
|
||||
|
||||
public void showActivity(ActivityType type) {
|
||||
panel.removeAll();
|
||||
panel.doLayout();
|
||||
|
||||
if (type == ActivityType.WORKING) {
|
||||
activityWorking.show();
|
||||
}
|
||||
else if (type == ActivityType.SETTINGS) {
|
||||
activitySettings.show();
|
||||
}
|
||||
|
||||
setVisible(true);
|
||||
panel.repaint();
|
||||
}
|
||||
|
||||
public void hideToTray() {
|
||||
if (sysTray == null || SystemTray.isSupported() == false) {
|
||||
Log.getInstance().debug("GuiSwing::hideToTray SystemTray not supported!");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
trayIcon = getTrayIcon();
|
||||
sysTray.add(trayIcon);
|
||||
}
|
||||
catch (AWTException e) {
|
||||
Log.getInstance().error("GuiSwing::hideToTray an error occured while trying to add system tray icon (exception: " + e + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
setVisible(false);
|
||||
|
||||
}
|
||||
|
||||
public void restoreFromTray() {
|
||||
if (sysTray != null && SystemTray.isSupported()) {
|
||||
sysTray.remove(trayIcon);
|
||||
setVisible(true);
|
||||
setExtendedState(getExtendedState() & ~ICONIFIED & NORMAL); // for toFront and requestFocus to actually work
|
||||
toFront();
|
||||
requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
public TrayIcon getTrayIcon() {
|
||||
final PopupMenu trayMenu = new PopupMenu();
|
||||
|
||||
// on start, show the base icon
|
||||
Image img = extractImageFromSprite(-1);
|
||||
final TrayIcon icon = new TrayIcon(img);
|
||||
|
||||
MenuItem exit = new MenuItem("Exit");
|
||||
exit.addActionListener(new ActionListener() {
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
trayMenu.add(exit);
|
||||
|
||||
MenuItem open = new MenuItem("Open...");
|
||||
open.addActionListener(new ActionListener() {
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
restoreFromTray();
|
||||
}
|
||||
});
|
||||
trayMenu.add(open);
|
||||
|
||||
MenuItem settings = new MenuItem("Settings...");
|
||||
settings.addActionListener(new ActionListener() {
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
restoreFromTray();
|
||||
showActivity(ActivityType.SETTINGS);
|
||||
}
|
||||
});
|
||||
trayMenu.add(settings);
|
||||
|
||||
icon.setPopupMenu(trayMenu);
|
||||
icon.setImageAutoSize(true);
|
||||
icon.setToolTip("SheepIt! Client");
|
||||
|
||||
icon.addActionListener(new ActionListener() {
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
restoreFromTray();
|
||||
}
|
||||
});
|
||||
|
||||
return icon;
|
||||
|
||||
}
|
||||
|
||||
public JPanel getContentPanel() {
|
||||
return this.panel;
|
||||
}
|
||||
|
||||
private Image extractImageFromSprite(int spriteNumber) {
|
||||
// Sprite structure
|
||||
// Image 0: base sprite
|
||||
// Images 1-101: progress bar percentage from 0 to 100
|
||||
//
|
||||
// Always add +1 to the icon requested.
|
||||
// -1 turns into 0 (base sprite with no progress bar)
|
||||
// 0 to 101 turns into 1 to 101 (progress sequence starts in sprite 1 and ends on sprite 101)
|
||||
ImageIcon img = new ImageIcon(iconSprites.getSubimage(0, (spriteNumber + 1) * 114, 114, 114));
|
||||
|
||||
return img.getImage();
|
||||
}
|
||||
|
||||
@Override public void updateTrayIcon(Integer percentage) {
|
||||
// update the app icon on the app bar
|
||||
Image img = extractImageFromSprite(percentage);
|
||||
setIconImage(img);
|
||||
|
||||
// if the app supports the system tray, update as well
|
||||
if (sysTray != null && SystemTray.isSupported() && trayIcon != null) {
|
||||
trayIcon.setImage(img);
|
||||
trayIcon.setImageAutoSize(true); // use this method to ensure that icon is refreshed when on
|
||||
// the tray
|
||||
}
|
||||
}
|
||||
|
||||
public class ThreadClient extends Thread {
|
||||
@Override public void run() {
|
||||
if (GuiSwing.this.client != null) {
|
||||
GuiSwing.this.client.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
222
src/main/java/com/sheepit/client/ui/GuiText.java
Normal file
222
src/main/java/com/sheepit/client/ui/GuiText.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2014 Laurent CLOUET
|
||||
* Author Laurent CLOUET <laurent.clouet@nopnop.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui;
|
||||
|
||||
import com.sheepit.client.Client;
|
||||
import com.sheepit.client.network.DownloadProgress;
|
||||
import com.sheepit.client.logger.Log;
|
||||
import com.sheepit.client.ui.text.CLIInputActionHandler;
|
||||
import com.sheepit.client.ui.text.CLIInputObserver;
|
||||
|
||||
import sun.misc.Signal;
|
||||
import sun.misc.SignalHandler;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
public class GuiText implements Gui {
|
||||
public static final String type = "text";
|
||||
|
||||
private int framesRendered;
|
||||
|
||||
private int sigIntCount = 0;
|
||||
private Log log;
|
||||
private DateFormat df;
|
||||
private String eta;
|
||||
private String statusOld; // buffer to avoid displaying the same info multiple time
|
||||
|
||||
private Client client;
|
||||
private DownloadProgress downloadProgress;
|
||||
|
||||
public GuiText() {
|
||||
this.downloadProgress = new DownloadProgress(this);
|
||||
this.framesRendered = 0;
|
||||
this.log = Log.getInstance();
|
||||
this.df = new SimpleDateFormat("MMM dd HH:mm:ss");
|
||||
this.eta = "";
|
||||
this.statusOld = "";
|
||||
}
|
||||
|
||||
@Override public void start() {
|
||||
if (client != null) {
|
||||
|
||||
CLIInputObserver cli_input_observer = new CLIInputObserver(client);
|
||||
cli_input_observer.addListener(new CLIInputActionHandler());
|
||||
Thread cli_input_observer_thread = new Thread(cli_input_observer);
|
||||
cli_input_observer_thread.start();
|
||||
|
||||
Signal.handle(new Signal("INT"), new SignalHandler() {
|
||||
@Override public void handle(Signal signal) {
|
||||
sigIntCount++;
|
||||
|
||||
if (sigIntCount == 4) {
|
||||
// This is only for ugly issues that might occur
|
||||
System.out.println("WARNING: Hitting Ctrl-C again will force close the application.");
|
||||
}
|
||||
else if (sigIntCount == 5) {
|
||||
Signal.raise(new Signal("INT"));
|
||||
Runtime.getRuntime().halt(0);
|
||||
}
|
||||
else if (client.isRunning() && client.isSuspended() == false) {
|
||||
client.askForStop();
|
||||
System.out.println("Will exit after current frame... Press Ctrl+C again to exit now.");
|
||||
}
|
||||
else {
|
||||
client.stop();
|
||||
GuiText.this.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.run();
|
||||
client.stop();
|
||||
}
|
||||
// stop if there is no client or client has been stopped
|
||||
this.stop();
|
||||
}
|
||||
|
||||
@Override public void stop() {
|
||||
Runtime.getRuntime().halt(0);
|
||||
}
|
||||
|
||||
@Override public void updateTrayIcon(Integer percentage) {
|
||||
}
|
||||
|
||||
@Override public void status(String msg_) {
|
||||
status(msg_, false);
|
||||
}
|
||||
|
||||
@Override public void status(String msg_, boolean overwriteSuspendedMsg) {
|
||||
log.debug("GUI " + msg_);
|
||||
|
||||
if (client != null && client.isSuspended()) {
|
||||
if (overwriteSuspendedMsg) {
|
||||
System.out.println(String.format("%s %s", this.df.format(new Date()), msg_));
|
||||
}
|
||||
}
|
||||
else {
|
||||
String statusNew = msg_;
|
||||
if (statusOld.equals(statusNew) == false) {
|
||||
statusOld = statusNew;
|
||||
System.out.println(String.format("%s %s", this.df.format(new Date()), msg_));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void status(String msg, int progress) {
|
||||
System.out.print("\r");
|
||||
System.out.print(String.format("%s %s", this.df.format(new Date()), showProgress(msg, progress)));
|
||||
}
|
||||
|
||||
@Override public void error(String err_) {
|
||||
System.out.println(String.format("ERROR: %s %s", this.df.format(new Date()), err_));
|
||||
log.error("Error " + err_);
|
||||
}
|
||||
|
||||
@Override public void AddFrameRendered() {
|
||||
this.framesRendered += 1;
|
||||
System.out.println(String.format("%s Frames rendered: %d", this.df.format(new Date()), this.framesRendered));
|
||||
}
|
||||
|
||||
@Override public synchronized void displayTransferStats(TransferStats downloads, TransferStats uploads) {
|
||||
System.out.println(String
|
||||
.format("%s Session downloads: %s @ %s/s / Uploads: %s @ %s/s", this.df.format(new Date()), downloads.getSessionTraffic(),
|
||||
downloads.getAverageSessionSpeed(), uploads.getSessionTraffic(), uploads.getAverageSessionSpeed()));
|
||||
}
|
||||
|
||||
@Override public void displayStats(Stats stats) {
|
||||
System.out.println(String.format("%s Frames remaining: %d", this.df.format(new Date()), stats.getRemainingFrame()));
|
||||
System.out.println(String.format("%s Credits earned: %d", this.df.format(new Date()), stats.getCreditsEarnedSession()));
|
||||
}
|
||||
|
||||
@Override public void displayUploadQueueStats(int queueSize, long queueVolume) {
|
||||
// No need to check if the queue is not empty to show the volume bc this line is always shown at the end
|
||||
// of the render process in text GUI (unless an error occurred, where the file is uploaded synchronously)
|
||||
System.out.println(String.format("%s Queued uploads: %d (%.2fMB)", this.df.format(new Date()), queueSize, (queueVolume / 1024.0 / 1024.0)));
|
||||
}
|
||||
|
||||
@Override public void setRenderingProjectName(String name_) {
|
||||
if (name_ != null && name_.isEmpty() == false) {
|
||||
System.out.println(String.format("%s Rendering project \"%s\"", this.df.format(new Date()), name_));
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setRemainingTime(String time_) {
|
||||
this.eta = time_;
|
||||
}
|
||||
|
||||
@Override public void setRenderingTime(String time_) {
|
||||
System.out.println(String.format("%s Rendering %s", this.df.format(new Date()), time_));
|
||||
}
|
||||
|
||||
@Override public void setClient(Client cli) {
|
||||
client = cli;
|
||||
}
|
||||
|
||||
@Override public void setComputeMethod(String computeMethod) {
|
||||
System.out.println(String.format("%s Compute method: %s", this.df.format(new Date()), computeMethod));
|
||||
}
|
||||
|
||||
@Override public Client getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override public DownloadProgress getDownloadProgress() {
|
||||
return downloadProgress;
|
||||
}
|
||||
|
||||
@Override public void successfulAuthenticationEvent(String publickey) {
|
||||
|
||||
}
|
||||
|
||||
private String showProgress(String message, int progress) {
|
||||
StringBuilder progressBar = new StringBuilder(140);
|
||||
|
||||
if (progress < 100) {
|
||||
progressBar
|
||||
.append(message)
|
||||
.append(" ")
|
||||
.append(String.join("", Collections.nCopies(progress == 0 ? 2 : 2 - (int) (Math.log10(progress)), " ")))
|
||||
.append(String.format("%d%% [", progress))
|
||||
.append(String.join("", Collections.nCopies((int)(progress/5), "=")))
|
||||
.append('>')
|
||||
.append(String.join("", Collections.nCopies(20 - (int)(progress / 5), " ")))
|
||||
.append(']');
|
||||
|
||||
if ("".equals(this.eta) == false) {
|
||||
progressBar.append(String.format(" ETA %s", this.eta));
|
||||
}
|
||||
|
||||
progressBar.append(String.join("", Collections.nCopies(60 - progressBar.length(), " ")));
|
||||
}
|
||||
// If progress has reached 100%
|
||||
else {
|
||||
progressBar
|
||||
.append(message)
|
||||
.append(" done")
|
||||
.append(String.join("", Collections.nCopies(60 - progressBar.length(), " ")))
|
||||
.append("\n");
|
||||
}
|
||||
|
||||
return progressBar.toString();
|
||||
}
|
||||
}
|
||||
242
src/main/java/com/sheepit/client/ui/GuiTextOneLine.java
Normal file
242
src/main/java/com/sheepit/client/ui/GuiTextOneLine.java
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Laurent CLOUET
|
||||
* Author Laurent CLOUET <laurent.clouet@nopnop.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui;
|
||||
|
||||
import com.sheepit.client.Client;
|
||||
import com.sheepit.client.network.DownloadProgress;
|
||||
import com.sheepit.client.ui.text.CLIInputActionHandler;
|
||||
import com.sheepit.client.ui.text.CLIInputObserver;
|
||||
|
||||
import sun.misc.Signal;
|
||||
import sun.misc.SignalHandler;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
public class GuiTextOneLine implements Gui {
|
||||
public static final String type = "oneLine";
|
||||
|
||||
private String project;
|
||||
private int rendered;
|
||||
private String creditsEarned;
|
||||
private int sigIntCount = 0;
|
||||
private DateFormat df;
|
||||
|
||||
private String computeMethod;
|
||||
private String status;
|
||||
private String line;
|
||||
private String eta;
|
||||
|
||||
private int uploadQueueSize;
|
||||
private long uploadQueueVolume;
|
||||
|
||||
private boolean exiting = false;
|
||||
|
||||
private Client client;
|
||||
private DownloadProgress downloadProgress;
|
||||
|
||||
public GuiTextOneLine() {
|
||||
downloadProgress = new DownloadProgress(this);
|
||||
project = "";
|
||||
rendered = 0;
|
||||
creditsEarned = null;
|
||||
status = "";
|
||||
computeMethod = "";
|
||||
line = "";
|
||||
uploadQueueSize = 0;
|
||||
uploadQueueVolume = 0;
|
||||
df = new SimpleDateFormat("MMM dd HH:mm:ss");
|
||||
eta = "";
|
||||
}
|
||||
|
||||
@Override public void start() {
|
||||
if (client != null) {
|
||||
|
||||
CLIInputObserver cli_input_observer = new CLIInputObserver(client);
|
||||
cli_input_observer.addListener(new CLIInputActionHandler());
|
||||
Thread cli_input_observer_thread = new Thread(cli_input_observer);
|
||||
cli_input_observer_thread.start();
|
||||
|
||||
Signal.handle(new Signal("INT"), new SignalHandler() {
|
||||
@Override public void handle(Signal signal) {
|
||||
sigIntCount++;
|
||||
|
||||
if (sigIntCount == 5) {
|
||||
Signal.raise(new Signal("INT"));
|
||||
Runtime.getRuntime().halt(0);
|
||||
}
|
||||
else if (client.isRunning() && client.isSuspended() == false) {
|
||||
client.askForStop();
|
||||
exiting = true;
|
||||
}
|
||||
else {
|
||||
client.stop();
|
||||
GuiTextOneLine.this.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.run();
|
||||
client.stop();
|
||||
}
|
||||
// stop if there is no client or client has been stopped
|
||||
this.stop();
|
||||
}
|
||||
|
||||
@Override public void stop() {
|
||||
Runtime.getRuntime().halt(0);
|
||||
}
|
||||
|
||||
@Override public void updateTrayIcon(Integer percentage) {
|
||||
}
|
||||
|
||||
@Override public void status(String msg_) {
|
||||
status(msg_, false);
|
||||
}
|
||||
|
||||
@Override public void status(String msg_, boolean overwriteSuspendedMsg) {
|
||||
if (client != null && client.isSuspended()) {
|
||||
if (overwriteSuspendedMsg) {
|
||||
status = msg_.replace("%", "%%"); // escape %
|
||||
updateLine();
|
||||
}
|
||||
}
|
||||
else {
|
||||
status = msg_.replace("%", "%%"); // escape %
|
||||
updateLine();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override public void status(String msg, int progress) {
|
||||
status = showProgress(msg, progress);
|
||||
updateLine();
|
||||
}
|
||||
|
||||
@Override public void setRenderingProjectName(String name_) {
|
||||
if (name_ == null || name_.isEmpty()) {
|
||||
project = "";
|
||||
}
|
||||
else {
|
||||
project = name_ + " |";
|
||||
}
|
||||
updateLine();
|
||||
}
|
||||
|
||||
@Override public void error(String msg_) {
|
||||
status = "Error " + msg_;
|
||||
updateLine();
|
||||
}
|
||||
|
||||
@Override public void AddFrameRendered() {
|
||||
rendered += 1;
|
||||
updateLine();
|
||||
}
|
||||
|
||||
@Override public synchronized void displayTransferStats(TransferStats downloads, TransferStats uploads) {
|
||||
// Session traffic stats not shown in the 1 line UI to avoid increasing the line length above 120 chars
|
||||
}
|
||||
|
||||
@Override public void displayStats(Stats stats) {
|
||||
creditsEarned = String.valueOf(stats.getCreditsEarnedSession());
|
||||
updateLine();
|
||||
}
|
||||
|
||||
@Override public void displayUploadQueueStats(int queueSize, long queueVolume) {
|
||||
this.uploadQueueSize = queueSize;
|
||||
this.uploadQueueVolume = queueVolume;
|
||||
}
|
||||
|
||||
@Override public void setRemainingTime(String time_) {
|
||||
this.eta = time_;
|
||||
updateLine();
|
||||
}
|
||||
|
||||
@Override public void setRenderingTime(String time_) {
|
||||
status = "Rendering " + time_;
|
||||
updateLine();
|
||||
}
|
||||
|
||||
@Override public void setClient(Client cli) {
|
||||
client = cli;
|
||||
}
|
||||
|
||||
@Override public DownloadProgress getDownloadProgress() {
|
||||
return downloadProgress;
|
||||
}
|
||||
|
||||
@Override public void setComputeMethod(String computeMethod_) {
|
||||
computeMethod = computeMethod_;
|
||||
}
|
||||
|
||||
@Override public Client getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override public void successfulAuthenticationEvent(String publickey) {
|
||||
|
||||
}
|
||||
|
||||
private void updateLine() {
|
||||
int charToRemove = line.length();
|
||||
|
||||
System.out.print("\r");
|
||||
|
||||
line = String.format("%s Frames: %d Points: %s | Upload Queue: %d%s | %%s %s %s", df.format(new Date()), rendered,
|
||||
creditsEarned != null ? creditsEarned : "unknown", this.uploadQueueSize,
|
||||
(this.uploadQueueSize > 0 ? String.format(" (%.2fMB)", (this.uploadQueueVolume / 1024.0 / 1024.0)) : ""), computeMethod,
|
||||
status + (exiting ? " (Exiting after all frames are uploaded)" : ""));
|
||||
|
||||
if (line.length() + project.length() > 120) {
|
||||
// If the line without the project name is already >120 characters (might happen if the user has thousands of frames and millions of points in the
|
||||
// session + is exiting after all frames are uploaded) then set the line to 117c to avoid a negative number exception in substring function
|
||||
int lineLength = Math.min(line.length(), 117);
|
||||
line = String.format(line, project.substring(0, 117 - lineLength) + "...");
|
||||
}
|
||||
else {
|
||||
line = String.format(line, project);
|
||||
}
|
||||
|
||||
System.out.print(line);
|
||||
for (int i = line.length(); i <= charToRemove; i++) {
|
||||
System.out.print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
private String showProgress(String message, int progress) {
|
||||
StringBuilder progressBar = new StringBuilder(140);
|
||||
progressBar
|
||||
.append(message)
|
||||
.append(String.join("", Collections.nCopies(progress == 0 ? 2 : 2 - (int) (Math.log10(progress)), " ")))
|
||||
.append(String.format(" %d%%%% [", progress))
|
||||
.append(String.join("", Collections.nCopies((int) (progress / 10), "=")))
|
||||
.append('>')
|
||||
.append(String.join("", Collections.nCopies(10 - (int) (progress / 10), " ")))
|
||||
.append(']');
|
||||
|
||||
if ("".equals(this.eta) == false) {
|
||||
progressBar.append(String.format(" ETA %s", this.eta));
|
||||
}
|
||||
|
||||
return progressBar.toString();
|
||||
}
|
||||
}
|
||||
37
src/main/java/com/sheepit/client/ui/Stats.java
Normal file
37
src/main/java/com/sheepit/client/ui/Stats.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Laurent CLOUET
|
||||
* Author Laurent CLOUET <laurent.clouet@nopnop.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data @AllArgsConstructor public class Stats {
|
||||
private int remainingFrame;
|
||||
private long creditsEarned;
|
||||
private int creditsEarnedSession;
|
||||
private int renderableProject;
|
||||
private int waitingProject;
|
||||
private int connectedMachine;
|
||||
|
||||
@Override public String toString() {
|
||||
return "Stats [remainingFrame=" + remainingFrame + ", creditsEarned=" + creditsEarned + ", creditsEarnedSession=" + creditsEarnedSession
|
||||
+ ", renderableProject=" + renderableProject + ", waitingProject=" + waitingProject + ", connectedMachine=" + connectedMachine + "]";
|
||||
}
|
||||
}
|
||||
41
src/main/java/com/sheepit/client/ui/TransferStats.java
Normal file
41
src/main/java/com/sheepit/client/ui/TransferStats.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package com.sheepit.client.ui;
|
||||
|
||||
import com.sheepit.client.utils.Utils;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/****************
|
||||
* Holds the session traffic statistics. The constructor accepts two parameters:
|
||||
* long bytes - bytes transferred in the session
|
||||
* long millis - milliseconds spent transferring the data
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class TransferStats {
|
||||
private long bytes;
|
||||
private long millis;
|
||||
|
||||
public TransferStats() {
|
||||
this.bytes = 0;
|
||||
this.millis = 0;
|
||||
}
|
||||
|
||||
public void calc(long bytes, long millis) {
|
||||
this.bytes += bytes;
|
||||
this.millis += millis;
|
||||
}
|
||||
|
||||
public String getSessionTraffic() {
|
||||
return Utils.formatDataConsumption(this.bytes);
|
||||
}
|
||||
|
||||
public String getAverageSessionSpeed() {
|
||||
try {
|
||||
return Utils.formatDataConsumption((long) (this.bytes / (this.millis / 1000f)));
|
||||
} catch (ArithmeticException e) { // Unlikely, but potential division by zero fallback if first transfer is done in zero millis
|
||||
return Utils.formatDataConsumption((long) (this.bytes / (0.1f)));
|
||||
}
|
||||
}
|
||||
|
||||
public long getRawAverageSessionSpeed() {
|
||||
return this.millis != 0 ? (long) (this.bytes / (this.millis / 1000f)) : 0;
|
||||
}
|
||||
}
|
||||
42
src/main/java/com/sheepit/client/ui/swing/SwingTooltips.java
Normal file
42
src/main/java/com/sheepit/client/ui/swing/SwingTooltips.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.sheepit.client.ui.swing;
|
||||
|
||||
public enum SwingTooltips {
|
||||
WORKING_DIRECTORY(
|
||||
"Where Sheepit stores things like downloaded projects, finished frames etc. Unless you want to free up your C: drive, Auto detected will do just fine."),
|
||||
|
||||
COMPUTE_DEVICES("What Sheepit will use to render. Note that only one device can be active at a time, e.g. sometimes you get jobs for your \n"
|
||||
+ "GPU so your CPU takes a break, sometimes it's the other way around. The only way to always use 100% of your system \n"
|
||||
+ "is to setup 2 clients, but for that you need to use the command line to give them different configs."),
|
||||
|
||||
CPU_CORES("How many (logical) cores of your CPU, often called threads, Sheepit may use. This doesn't apply to GPU-jobs.\n"
|
||||
+ "(Note that GPU jobs will also use CPU cores for scene building and feeding the GPU)\n"),
|
||||
|
||||
MEMORY("How much RAM Sheepit may use. This isn't a 100% safe limit, since Blender can erroneously use more, \n"
|
||||
+ "but Sheepit will try its best to give you jobs that require less than what you've entered here."),
|
||||
|
||||
PRIORITY("Which priority in your system the rendering process should have."),
|
||||
|
||||
MINIMIZE_TO_SYSTRAY("Whether Sheepit should vanish into your system tray (the icons next to the clock in the bottom right) when you minimize the window."),
|
||||
|
||||
PROXY("If you don't know what this does, you don't need it. Useful for example if you're in a company network with restricted access."),
|
||||
|
||||
COMPUTER_NAME("What this machine will be displayed as on your Sheepit profile page. Only you and admins can see this."),
|
||||
|
||||
INCOMPATIBLE_PROCESS("If your specified process starts or is running, SheepIt will stop the current render job and pause. For example, if we take Firefox the formatting is firefox.exe on Windows and firefox on Linux."),
|
||||
|
||||
MAX_TIME_PER_FRAME("How much time a frame should take at most. Sheepit will try to assign jobs to your machine that take less time to compute."),
|
||||
|
||||
DISABLE_LARGE_DOWNLOADS("Limits the client to smaller projects <= 750 MB. Consider this option if you are on a metered connection");
|
||||
|
||||
|
||||
private final String explanation;
|
||||
|
||||
private SwingTooltips(String explanation) {
|
||||
this.explanation = explanation;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return explanation;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Laurent CLOUET
|
||||
* Author Laurent CLOUET <laurent.clouet@nopnop.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui.swing.activity;
|
||||
|
||||
public interface Activity {
|
||||
|
||||
public void show();
|
||||
|
||||
public void resizeWindow();
|
||||
|
||||
}
|
||||
905
src/main/java/com/sheepit/client/ui/swing/activity/Settings.java
Normal file
905
src/main/java/com/sheepit/client/ui/swing/activity/Settings.java
Normal file
@@ -0,0 +1,905 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Laurent CLOUET
|
||||
* Author Laurent CLOUET <laurent.clouet@nopnop.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui.swing.activity;
|
||||
|
||||
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.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Hashtable;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPasswordField;
|
||||
import javax.swing.JRadioButton;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.formdev.flatlaf.FlatDarkLaf;
|
||||
|
||||
import com.sheepit.client.config.Configuration;
|
||||
import com.sheepit.client.config.Configuration.ComputeType;
|
||||
import com.sheepit.client.config.DirectoryManager;
|
||||
import com.sheepit.client.hardware.cpu.CPU;
|
||||
import com.sheepit.client.hardware.gpu.GPU;
|
||||
import com.sheepit.client.hardware.gpu.GPUDevice;
|
||||
import com.sheepit.client.network.proxy.Proxy;
|
||||
import com.sheepit.client.os.OS;
|
||||
import com.sheepit.client.ui.GuiSwing;
|
||||
import com.sheepit.client.ui.swing.SwingTooltips;
|
||||
import com.sheepit.client.ui.swing.components.CollapsibleJPanel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class Settings implements Activity {
|
||||
private static final String DUMMY_CACHE_DIR = "Auto detected";
|
||||
|
||||
private GuiSwing parent;
|
||||
|
||||
private JTextField login;
|
||||
private JPasswordField password;
|
||||
private JLabel cacheDirText;
|
||||
private File cacheDir;
|
||||
private JFileChooser cacheDirChooser;
|
||||
private JCheckBox useCPU;
|
||||
private List<JCheckBoxGPU> useGPUs;
|
||||
private JCheckBox useSysTray;
|
||||
private JCheckBox headlessCheckbox;
|
||||
private JSlider cpuCores;
|
||||
private JSlider ram;
|
||||
private JSpinner renderTime;
|
||||
private JSlider priority;
|
||||
private JTextField proxy;
|
||||
private JTextField hostname;
|
||||
private JCheckBox disableLargeDownloads;
|
||||
private JTextField incompatibleProcess;
|
||||
|
||||
private ButtonGroup themeOptionsGroup;
|
||||
private JRadioButton lightMode;
|
||||
private JRadioButton darkMode;
|
||||
|
||||
private JCheckBox saveFile;
|
||||
private JCheckBox autoSignIn;
|
||||
JButton cancelButton;
|
||||
JButton saveButton;
|
||||
|
||||
private boolean haveAutoStarted;
|
||||
private boolean useSysTrayPrevState;
|
||||
private boolean isHeadlessPrevState;
|
||||
private boolean disableLargeDownloadsPrevState;
|
||||
private boolean sessionStarted; //indicates whether the settings activity gets shown on launch or mid-session.
|
||||
// it should only be false when the settings activity gets shown right after launch
|
||||
|
||||
public Settings(GuiSwing parent_) {
|
||||
parent = parent_;
|
||||
cacheDir = null;
|
||||
useGPUs = new LinkedList<JCheckBoxGPU>();
|
||||
haveAutoStarted = false;
|
||||
sessionStarted = false;
|
||||
}
|
||||
|
||||
@Override public void show() {
|
||||
Configuration config = parent.getConfiguration();
|
||||
parent.getSettingsLoader().merge(config, false);
|
||||
useSysTrayPrevState = config.isUseSysTray();
|
||||
isHeadlessPrevState = config.isHeadless();
|
||||
disableLargeDownloadsPrevState = config.isDisableLargeDownloads();
|
||||
|
||||
applyTheme(config.getTheme()); // apply the proper theme (light/dark)
|
||||
|
||||
List<GPUDevice> gpus = GPU.listDevices(config);
|
||||
useGPUs.clear(); // Empty the auxiliary list (used in the list of checkboxes)
|
||||
|
||||
GridBagConstraints constraints = new GridBagConstraints();
|
||||
int currentRow = 0;
|
||||
|
||||
JLabel labelImage = GuiSwing.createLogoWithWatermark();
|
||||
|
||||
constraints.fill = GridBagConstraints.CENTER;
|
||||
|
||||
constraints.gridwidth = 2;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = currentRow;
|
||||
parent.getContentPanel().add(labelImage, constraints);
|
||||
|
||||
++currentRow;
|
||||
|
||||
constraints.gridy = currentRow;
|
||||
parent.getContentPanel().add(new JLabel(" "), constraints); // Add a separator between logo and first panel
|
||||
|
||||
currentRow++;
|
||||
|
||||
// authentication
|
||||
CollapsibleJPanel authentication_panel = new CollapsibleJPanel(new GridLayout(2, 2), this);
|
||||
authentication_panel.setBorder(BorderFactory.createTitledBorder("Authentication"));
|
||||
|
||||
JLabel loginLabel = new JLabel("Username:");
|
||||
login = new JTextField();
|
||||
login.setText(parent.getConfiguration().getLogin());
|
||||
login.setColumns(20);
|
||||
login.addKeyListener(new CheckCanStart());
|
||||
JLabel passwordLabel = new JLabel("Password:");
|
||||
password = new JPasswordField();
|
||||
password.setText(parent.getConfiguration().getPassword());
|
||||
password.setColumns(10);
|
||||
password.addKeyListener(new CheckCanStart());
|
||||
|
||||
authentication_panel.add(loginLabel);
|
||||
authentication_panel.add(login);
|
||||
|
||||
authentication_panel.add(passwordLabel);
|
||||
authentication_panel.add(password);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = currentRow;
|
||||
constraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
parent.getContentPanel().add(authentication_panel, constraints);
|
||||
|
||||
// Theme selection panel
|
||||
CollapsibleJPanel themePanel = new CollapsibleJPanel(new GridLayout(1, 3), this);
|
||||
themePanel.setBorder(BorderFactory.createTitledBorder("Theme"));
|
||||
|
||||
themeOptionsGroup = new ButtonGroup();
|
||||
|
||||
lightMode = new JRadioButton("Light");
|
||||
lightMode.setActionCommand("light");
|
||||
lightMode.setSelected("light".equals(config.getTheme()));
|
||||
lightMode.addActionListener(new ApplyThemeAction());
|
||||
|
||||
darkMode = new JRadioButton("Dark");
|
||||
darkMode.setActionCommand("dark");
|
||||
darkMode.setSelected("dark".equals(config.getTheme()));
|
||||
darkMode.addActionListener(new ApplyThemeAction());
|
||||
|
||||
themePanel.add(lightMode);
|
||||
themePanel.add(darkMode);
|
||||
|
||||
// Group both radio buttons to allow only one selected
|
||||
themeOptionsGroup.add(lightMode);
|
||||
themeOptionsGroup.add(darkMode);
|
||||
|
||||
currentRow++;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = currentRow;
|
||||
constraints.gridwidth = 2;
|
||||
|
||||
parent.getContentPanel().add(themePanel, constraints);
|
||||
|
||||
// directory
|
||||
CollapsibleJPanel directory_panel = new CollapsibleJPanel(new GridLayout(1, 3), this);
|
||||
directory_panel.setBorder(BorderFactory.createTitledBorder("Cache"));
|
||||
JLabel cacheLabel = new JLabel("Working directory:");
|
||||
cacheLabel.setToolTipText(SwingTooltips.WORKING_DIRECTORY.getText());
|
||||
directory_panel.add(cacheLabel);
|
||||
String destination = DUMMY_CACHE_DIR;
|
||||
if (config.isUserHasSpecifiedACacheDir()) {
|
||||
destination = config.getCacheDirForSettings().getName();
|
||||
}
|
||||
|
||||
JPanel cacheDirWrapper = new JPanel();
|
||||
cacheDirWrapper.setLayout(new BoxLayout(cacheDirWrapper, BoxLayout.LINE_AXIS));
|
||||
cacheDirText = new JLabel(destination);
|
||||
cacheDirWrapper.add(cacheDirText);
|
||||
|
||||
cacheDirWrapper.add(Box.createHorizontalGlue());
|
||||
|
||||
cacheDirChooser = new JFileChooser();
|
||||
cacheDirChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
JButton openButton = new JButton("...");
|
||||
openButton.addActionListener(new ChooseFileAction());
|
||||
cacheDirWrapper.add(openButton);
|
||||
|
||||
directory_panel.add(cacheDirWrapper);
|
||||
|
||||
currentRow++;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = currentRow;
|
||||
constraints.gridwidth = 2;
|
||||
|
||||
parent.getContentPanel().add(directory_panel, constraints);
|
||||
|
||||
// compute devices
|
||||
GridBagLayout gridbag = new GridBagLayout();
|
||||
GridBagConstraints compute_devices_constraints = new GridBagConstraints();
|
||||
CollapsibleJPanel compute_devices_panel = new CollapsibleJPanel(gridbag, this);
|
||||
|
||||
compute_devices_panel.setBorder(BorderFactory.createTitledBorder("Compute devices"));
|
||||
compute_devices_panel.setToolTipText(SwingTooltips.COMPUTE_DEVICES.getText());
|
||||
|
||||
ComputeType method = config.getComputeMethod();
|
||||
useCPU = new JCheckBox("CPU");
|
||||
boolean gpuChecked = false;
|
||||
|
||||
if (method == ComputeType.CPU_GPU) {
|
||||
useCPU.setSelected(true);
|
||||
gpuChecked = true;
|
||||
}
|
||||
else if (method == ComputeType.CPU) {
|
||||
useCPU.setSelected(true);
|
||||
gpuChecked = false;
|
||||
}
|
||||
else if (method == ComputeType.GPU) {
|
||||
useCPU.setSelected(false);
|
||||
gpuChecked = true;
|
||||
}
|
||||
useCPU.addActionListener(new CpuChangeAction());
|
||||
|
||||
compute_devices_constraints.gridx = 1;
|
||||
compute_devices_constraints.gridy = 0;
|
||||
compute_devices_constraints.fill = GridBagConstraints.BOTH;
|
||||
compute_devices_constraints.weightx = 1.0;
|
||||
compute_devices_constraints.weighty = 1.0;
|
||||
|
||||
gridbag.setConstraints(useCPU, compute_devices_constraints);
|
||||
compute_devices_panel.add(useCPU);
|
||||
|
||||
if (gpus.isEmpty() == false || GPU.hasHIPDevices()) {
|
||||
for (GPUDevice gpu : gpus) {
|
||||
JCheckBoxGPU gpuCheckBox = new JCheckBoxGPU(gpu);
|
||||
gpuCheckBox.setToolTipText(gpu.getId());
|
||||
if (gpuChecked) {
|
||||
GPUDevice config_gpu = config.getGPUDevice();
|
||||
if (config_gpu != null && config_gpu.getId().equals(gpu.getId())) {
|
||||
gpuCheckBox.setSelected(gpuChecked);
|
||||
}
|
||||
}
|
||||
gpuCheckBox.addActionListener(new GpuChangeAction());
|
||||
|
||||
compute_devices_constraints.gridy++;
|
||||
gridbag.setConstraints(gpuCheckBox, compute_devices_constraints);
|
||||
compute_devices_panel.add(gpuCheckBox);
|
||||
useGPUs.add(gpuCheckBox);
|
||||
}
|
||||
|
||||
if (GPU.hasHIPDevices()) {
|
||||
JCheckBox gpuCheckBox = new JCheckBox("Unsupported HIP device(s)");
|
||||
gpuCheckBox.setToolTipText("SheepIt does not support AMD GPUs due to a lack of use");
|
||||
gpuCheckBox.setEnabled(false);
|
||||
gpuCheckBox.setSelected(false);
|
||||
compute_devices_constraints.gridy++;
|
||||
|
||||
gridbag.setConstraints(gpuCheckBox, compute_devices_constraints);
|
||||
compute_devices_panel.add(gpuCheckBox);
|
||||
}
|
||||
|
||||
compute_devices_constraints.gridx = 1;
|
||||
compute_devices_constraints.weightx = 1.0;
|
||||
|
||||
compute_devices_panel.add(new JLabel(" "), compute_devices_constraints); // Add a space between lines
|
||||
}
|
||||
|
||||
|
||||
CPU cpu = new CPU();
|
||||
if (cpu.cores() > 1) { // if only one core is available, no need to show the choice
|
||||
double step = 1;
|
||||
double display = (double) cpu.cores() / step;
|
||||
while (display > 10) {
|
||||
step += 1.0;
|
||||
display = (double) cpu.cores() / step;
|
||||
}
|
||||
|
||||
cpuCores = new JSlider(CPU.MIN_CORES, cpu.cores());
|
||||
cpuCores.setMajorTickSpacing((int) (step));
|
||||
cpuCores.setMinorTickSpacing(1);
|
||||
cpuCores.setPaintTicks(true);
|
||||
cpuCores.setSnapToTicks(true);
|
||||
cpuCores.addChangeListener(new ChangeListener() {
|
||||
@Override public void stateChanged(ChangeEvent e) {
|
||||
cpuCores.setToolTipText(String.valueOf(cpuCores.getValue()));
|
||||
}
|
||||
});
|
||||
cpuCores.setPaintLabels(true);
|
||||
cpuCores.setValue(config.getNbCores() != -1 ? (Math.max(config.getNbCores(), CPU.MIN_CORES)): cpuCores.getMaximum());
|
||||
JLabel coreLabel = new JLabel("CPU cores:");
|
||||
coreLabel.setToolTipText(SwingTooltips.CPU_CORES.getText());
|
||||
|
||||
compute_devices_constraints.weightx = 1.0 / gpus.size();
|
||||
compute_devices_constraints.gridx = 0;
|
||||
compute_devices_constraints.gridy++;
|
||||
|
||||
gridbag.setConstraints(coreLabel, compute_devices_constraints);
|
||||
compute_devices_panel.add(coreLabel);
|
||||
|
||||
compute_devices_constraints.gridx = 1;
|
||||
compute_devices_constraints.weightx = 1.0;
|
||||
|
||||
gridbag.setConstraints(cpuCores, compute_devices_constraints);
|
||||
compute_devices_panel.add(new JLabel(" "), compute_devices_constraints); // Add a space between lines
|
||||
compute_devices_panel.add(cpuCores);
|
||||
}
|
||||
|
||||
// max ram allowed to render
|
||||
OS os = OS.getOS();
|
||||
int all_ram = (int) os.getTotalMemory();
|
||||
ram = new JSlider(0, all_ram);
|
||||
int step = 1000000;
|
||||
double display = (double) all_ram / (double) step;
|
||||
while (display > 10) {
|
||||
step += 1000000;
|
||||
display = (double) all_ram / (double) step;
|
||||
}
|
||||
Dictionary<Integer, JLabel> labelTable = new Hashtable<>();
|
||||
for (int g = 0; g < all_ram; g += step) {
|
||||
labelTable.put(g, new JLabel("" + (g / 1000000)));
|
||||
}
|
||||
ram.setMajorTickSpacing(step);
|
||||
ram.setLabelTable(labelTable);
|
||||
ram.setPaintTicks(true);
|
||||
ram.addChangeListener(new ChangeListener() {
|
||||
@Override public void stateChanged(ChangeEvent e) {
|
||||
ram.setToolTipText(String.format("%,d MiB", (ram.getValue() / 1024)));
|
||||
}
|
||||
});
|
||||
ram.setPaintLabels(true);
|
||||
ram.setValue((int) (config.getMaxAllowedMemory() != -1 ? config.getMaxAllowedMemory() : os.getTotalMemory()));
|
||||
JLabel ramLabel = new JLabel("Memory:");
|
||||
ramLabel.setToolTipText(SwingTooltips.MEMORY.getText());
|
||||
|
||||
compute_devices_constraints.weightx = 1.0 / gpus.size();
|
||||
compute_devices_constraints.gridx = 0;
|
||||
compute_devices_constraints.gridy++;
|
||||
|
||||
gridbag.setConstraints(ramLabel, compute_devices_constraints);
|
||||
compute_devices_panel.add(ramLabel);
|
||||
|
||||
compute_devices_constraints.gridx = 1;
|
||||
compute_devices_constraints.weightx = 1.0;
|
||||
|
||||
gridbag.setConstraints(ram, compute_devices_constraints);
|
||||
compute_devices_panel.add(new JLabel(" "), compute_devices_constraints); // Add a space between lines
|
||||
compute_devices_panel.add(ram);
|
||||
|
||||
parent.getContentPanel().add(compute_devices_panel, constraints);
|
||||
|
||||
// priority
|
||||
// ui display low -> high but the actual values are reversed
|
||||
// -19 is highest priority
|
||||
boolean high_priority_support = os.isHighPrioritySupported();
|
||||
priority = new JSlider(high_priority_support ? -19 : 0, 19);
|
||||
Dictionary<Integer, JLabel> labelTablePriority = new Hashtable<>();
|
||||
labelTablePriority.put(high_priority_support ? -19 : 0, new JLabel("Low"));
|
||||
labelTablePriority.put(19, new JLabel("High"));
|
||||
priority.setLabelTable(labelTablePriority);
|
||||
|
||||
priority.setMinorTickSpacing(1);
|
||||
priority.setPaintTicks(true);
|
||||
priority.setSnapToTicks(true);
|
||||
priority.addChangeListener(new ChangeListener() {
|
||||
@Override public void stateChanged(ChangeEvent e) {
|
||||
priority.setToolTipText(String.valueOf(priority.getValue()));
|
||||
}
|
||||
});
|
||||
priority.setPaintLabels(true);
|
||||
if (high_priority_support) {
|
||||
// inverse
|
||||
priority.setValue(-1 * config.getPriority());
|
||||
}
|
||||
else {
|
||||
priority.setValue(19 - config.getPriority());
|
||||
}
|
||||
JLabel priorityLabel = new JLabel("Priority");
|
||||
priorityLabel.setToolTipText(SwingTooltips.PRIORITY.getText());
|
||||
|
||||
boolean showPrioritySlider = os.isNiceAvailable();
|
||||
priority.setVisible(showPrioritySlider);
|
||||
priorityLabel.setVisible(showPrioritySlider);
|
||||
|
||||
compute_devices_constraints.weightx = 1.0 / gpus.size();
|
||||
compute_devices_constraints.gridx = 0;
|
||||
compute_devices_constraints.gridy++;
|
||||
|
||||
gridbag.setConstraints(priorityLabel, compute_devices_constraints);
|
||||
compute_devices_panel.add(priorityLabel);
|
||||
|
||||
compute_devices_constraints.gridx = 1;
|
||||
compute_devices_constraints.weightx = 1.0;
|
||||
|
||||
gridbag.setConstraints(priority, compute_devices_constraints);
|
||||
compute_devices_panel.add(priority);
|
||||
|
||||
currentRow++;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = currentRow;
|
||||
constraints.gridwidth = 2;
|
||||
parent.getContentPanel().add(compute_devices_panel, constraints);
|
||||
|
||||
// other
|
||||
CollapsibleJPanel advanced_panel = new CollapsibleJPanel(new GridLayout(7, 2), this);
|
||||
advanced_panel.setBorder(BorderFactory.createTitledBorder("Advanced options"));
|
||||
|
||||
JLabel useSysTrayLabel = new JLabel("Minimize to SysTray");
|
||||
useSysTrayLabel.setToolTipText(SwingTooltips.MINIMIZE_TO_SYSTRAY.getText());
|
||||
|
||||
useSysTray = new JCheckBox();
|
||||
useSysTray.setSelected(config.isUseSysTray());
|
||||
advanced_panel.add(useSysTrayLabel);
|
||||
advanced_panel.add(useSysTray);
|
||||
|
||||
JLabel headlessLabel = new JLabel("Block Eevee projects");
|
||||
headlessCheckbox = new JCheckBox();
|
||||
headlessCheckbox.setSelected(config.isHeadless());
|
||||
advanced_panel.add(headlessLabel);
|
||||
advanced_panel.add(headlessCheckbox);
|
||||
|
||||
JLabel disableLargeDownloadsLabel = new JLabel("Disable large downloads");
|
||||
disableLargeDownloads = new JCheckBox();
|
||||
disableLargeDownloads.setSelected(config.isDisableLargeDownloads());
|
||||
disableLargeDownloadsLabel.setToolTipText(SwingTooltips.DISABLE_LARGE_DOWNLOADS.getText());
|
||||
advanced_panel.add(disableLargeDownloadsLabel);
|
||||
advanced_panel.add(disableLargeDownloads);
|
||||
|
||||
JLabel proxyLabel = new JLabel("Proxy:");
|
||||
proxyLabel.setToolTipText("http://login:password@host:port\n" + SwingTooltips.PROXY.getText());
|
||||
proxy = new JTextField();
|
||||
proxy.setToolTipText("http://login:password@host:port");
|
||||
proxy.setText(parent.getConfiguration().getProxy());
|
||||
proxy.addKeyListener(new CheckCanStart());
|
||||
|
||||
advanced_panel.add(proxyLabel);
|
||||
advanced_panel.add(proxy);
|
||||
|
||||
JLabel hostnameLabel = new JLabel("Computer name:");
|
||||
hostnameLabel.setToolTipText(SwingTooltips.COMPUTER_NAME.getText());
|
||||
hostname = new JTextField();
|
||||
hostname.setText(parent.getConfiguration().getHostname());
|
||||
|
||||
advanced_panel.add(hostnameLabel);
|
||||
advanced_panel.add(hostname);
|
||||
|
||||
JLabel incompatibleProcessLabel = new JLabel("Incompatible process:");
|
||||
incompatibleProcessLabel.setToolTipText(SwingTooltips.INCOMPATIBLE_PROCESS.getText());
|
||||
incompatibleProcess = new JTextField();
|
||||
incompatibleProcess.setText(parent.getConfiguration().getIncompatibleProcess());
|
||||
|
||||
advanced_panel.add(incompatibleProcessLabel);
|
||||
advanced_panel.add(incompatibleProcess);
|
||||
|
||||
JLabel renderTimeLabel = new JLabel("Max time per frame (in minute):");
|
||||
renderTimeLabel.setToolTipText(SwingTooltips.MAX_TIME_PER_FRAME.getText());
|
||||
int val = 0;
|
||||
if (parent.getConfiguration().getMaxRenderTime() > 0) {
|
||||
val = parent.getConfiguration().getMaxRenderTime() / 60;
|
||||
}
|
||||
renderTime = new JSpinner(new SpinnerNumberModel(val, 0, 1000, 1));
|
||||
|
||||
advanced_panel.add(renderTimeLabel);
|
||||
advanced_panel.add(renderTime);
|
||||
|
||||
currentRow++;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = currentRow;
|
||||
constraints.gridwidth = 2;
|
||||
parent.getContentPanel().add(advanced_panel, constraints);
|
||||
|
||||
// general settings
|
||||
JPanel general_panel = new JPanel(new GridLayout(1, 2));
|
||||
|
||||
saveFile = new JCheckBox("Write settings to file", true);
|
||||
saveFile.addActionListener(new SaveSettingsFileAction());
|
||||
general_panel.add(saveFile);
|
||||
|
||||
autoSignIn = new JCheckBox("Auto sign in", config.isAutoSignIn());
|
||||
autoSignIn.addActionListener(new AutoSignInChangeAction());
|
||||
general_panel.add(autoSignIn);
|
||||
|
||||
currentRow++;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = currentRow;
|
||||
constraints.gridwidth = 2;
|
||||
parent.getContentPanel().add(general_panel, constraints);
|
||||
|
||||
currentRow++;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = currentRow;
|
||||
constraints.gridwidth = 2;
|
||||
parent.getContentPanel().add(new JLabel(" "), constraints); // Add a separator between last checkboxes and button
|
||||
|
||||
// Close buttons (Discard / Save)
|
||||
// Only show Discard button if there is a client running to close back to
|
||||
boolean isClientRunning = parent.getClient() != null && parent.getClient().isRunning();
|
||||
int savePanelCols = isClientRunning ? 2 : 1;
|
||||
JPanel savePanel = new JPanel(new GridLayout(1, savePanelCols));
|
||||
|
||||
if (isClientRunning) {
|
||||
cancelButton = new JButton("Discard & go back");
|
||||
cancelButton.addActionListener(new CancelAction());
|
||||
savePanel.add(cancelButton);
|
||||
}
|
||||
|
||||
saveButton = new JButton("Save & go back");
|
||||
checkDisplaySaveButton(); // Sets the button text and enabled state
|
||||
saveButton.addActionListener(new SaveAction());
|
||||
savePanel.add(saveButton);
|
||||
|
||||
currentRow++;
|
||||
constraints.gridwidth = 2;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = currentRow;
|
||||
parent.getContentPanel().add(savePanel, constraints);
|
||||
|
||||
// Increase the size of the app Window to ensure it shows all the information with the Advanced Options panel opened.
|
||||
parent.setSize(GuiSwing.WIDTH, 850);
|
||||
|
||||
if (haveAutoStarted == false && config.isAutoSignIn() && checkDisplaySaveButton()) {
|
||||
// auto start
|
||||
haveAutoStarted = true;
|
||||
new SaveAction().actionPerformed(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void resizeWindow() {}
|
||||
|
||||
public boolean checkDisplaySaveButton() {
|
||||
boolean selected = useCPU.isSelected();
|
||||
for (JCheckBoxGPU box : useGPUs) {
|
||||
if (box.isSelected()) {
|
||||
selected = true;
|
||||
}
|
||||
}
|
||||
if (login.getText().isEmpty() || password.getPassword().length == 0 || Proxy.isValidURL(proxy.getText()) == false) {
|
||||
selected = false;
|
||||
}
|
||||
|
||||
boolean isClientRunning = parent.getClient() != null && parent.getClient().isRunning();
|
||||
if (isClientRunning) {
|
||||
if (saveFile.isSelected()) {
|
||||
saveButton.setText("Save & go back");
|
||||
} else {
|
||||
saveButton.setText("Apply & go back");
|
||||
}
|
||||
} else {
|
||||
if (saveFile.isSelected()) {
|
||||
saveButton.setText("Save & start");
|
||||
} else {
|
||||
saveButton.setText("Apply & start");
|
||||
}
|
||||
}
|
||||
saveButton.setEnabled(selected);
|
||||
return selected;
|
||||
}
|
||||
|
||||
private void applyTheme(String theme_) {
|
||||
try {
|
||||
if ("light".equals(theme_)) {
|
||||
UIManager.setLookAndFeel(new FlatLightLaf());
|
||||
}
|
||||
else if ("dark".equals(theme_)) {
|
||||
UIManager.setLookAndFeel(new FlatDarkLaf());
|
||||
}
|
||||
|
||||
// Apply the new theme
|
||||
FlatLaf.updateUI();
|
||||
}
|
||||
catch (UnsupportedLookAndFeelException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
class ChooseFileAction implements ActionListener {
|
||||
|
||||
@Override public void actionPerformed(ActionEvent arg0) {
|
||||
JOptionPane.showMessageDialog(parent.getContentPane(),
|
||||
"<html>The working directory has to be dedicated directory. <br />Caution, everything not related to SheepIt-Renderfarm will be removed.<br />You should create a directory specifically for it.</html>",
|
||||
"Warning: files will be removed!", JOptionPane.WARNING_MESSAGE);
|
||||
int returnVal = cacheDirChooser.showOpenDialog(parent.getContentPane());
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
File file = cacheDirChooser.getSelectedFile();
|
||||
cacheDir = file;
|
||||
cacheDirText.setText(cacheDir.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CpuChangeAction implements ActionListener {
|
||||
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
checkDisplaySaveButton();
|
||||
}
|
||||
}
|
||||
|
||||
class GpuChangeAction implements ActionListener {
|
||||
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
for (JCheckBox box : useGPUs) {
|
||||
if (!box.isSelected()) {
|
||||
box.setSelected(false);
|
||||
}
|
||||
|
||||
// Simulate a radio button behavior with check buttons while only 1 GPU
|
||||
// can be selected at a time
|
||||
if (box.equals(e.getSource()) == false) {
|
||||
box.setSelected(false);
|
||||
}
|
||||
}
|
||||
checkDisplaySaveButton();
|
||||
}
|
||||
}
|
||||
|
||||
class AutoSignInChangeAction implements ActionListener {
|
||||
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
if (autoSignIn.isSelected()) {
|
||||
saveFile.setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ApplyThemeAction implements ActionListener {
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
applyTheme(themeOptionsGroup.getSelection().getActionCommand());
|
||||
}
|
||||
}
|
||||
|
||||
class CancelAction implements ActionListener {
|
||||
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Configuration config = parent.getConfiguration();
|
||||
if (config == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyTheme(config.getTheme()); // apply the proper theme (light/dark)
|
||||
|
||||
parent.showActivity(GuiSwing.ActivityType.WORKING);
|
||||
}
|
||||
}
|
||||
|
||||
class SaveAction implements ActionListener {
|
||||
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Configuration config = parent.getConfiguration();
|
||||
if (config == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (themeOptionsGroup.getSelection().getActionCommand() != null)
|
||||
config.setTheme(themeOptionsGroup.getSelection().getActionCommand());
|
||||
|
||||
if (cacheDir != null) {
|
||||
File fromConfig = config.getWorkingDirectory();
|
||||
if (fromConfig != null && fromConfig.getAbsolutePath().equals(cacheDir.getAbsolutePath()) == false) {
|
||||
config.setCacheDir(cacheDir);
|
||||
(new DirectoryManager(config)).createCacheDir();
|
||||
}
|
||||
else {
|
||||
// do nothing because the directory is the same as before
|
||||
}
|
||||
}
|
||||
|
||||
GPUDevice selected_gpu = null;
|
||||
for (JCheckBoxGPU box : useGPUs) {
|
||||
if (box.isSelected()) {
|
||||
selected_gpu = box.getGPUDevice();
|
||||
}
|
||||
}
|
||||
|
||||
ComputeType method = getComputeType(selected_gpu);
|
||||
config.setComputeMethod(method);
|
||||
|
||||
if (selected_gpu != null) {
|
||||
config.setGPUDevice(selected_gpu);
|
||||
}
|
||||
|
||||
int cpu_cores = -1;
|
||||
if (cpuCores != null) {
|
||||
cpu_cores = cpuCores.getValue();
|
||||
}
|
||||
|
||||
if (cpu_cores > 0) {
|
||||
config.setNbCores(cpu_cores);
|
||||
}
|
||||
|
||||
long max_ram = -1;
|
||||
if (ram != null) {
|
||||
max_ram = ram.getValue();
|
||||
}
|
||||
|
||||
if (max_ram > 0) {
|
||||
config.setMaxAllowedMemory(max_ram);
|
||||
}
|
||||
|
||||
int max_rendertime = -1;
|
||||
if (renderTime != null) {
|
||||
max_rendertime = (Integer) renderTime.getValue() * 60;
|
||||
config.setMaxRenderTime(max_rendertime);
|
||||
}
|
||||
|
||||
// ui display low -> high but the actual values are reversed
|
||||
// -19 is highest priority
|
||||
OS os = OS.getOS();
|
||||
boolean high_priority_support = os.isHighPrioritySupported();
|
||||
if (high_priority_support) {
|
||||
// inverse
|
||||
config.setPriority(-1 * priority.getValue());
|
||||
}
|
||||
else {
|
||||
config.setPriority(19 - priority.getValue());
|
||||
}
|
||||
|
||||
config.setHeadless(headlessCheckbox.isSelected());
|
||||
|
||||
config.setDisableLargeDownloads(disableLargeDownloads.isSelected());
|
||||
|
||||
String proxyText = null;
|
||||
if (proxy != null) {
|
||||
try {
|
||||
Proxy.set(proxy.getText());
|
||||
proxyText = proxy.getText();
|
||||
}
|
||||
catch (MalformedURLException e1) {
|
||||
System.err.println("Error: wrong url for proxy");
|
||||
System.err.println(e1);
|
||||
System.exit(2);
|
||||
}
|
||||
}
|
||||
config.setProxy(proxyText);
|
||||
|
||||
parent.setCredentials(login.getText(), new String(password.getPassword()));
|
||||
|
||||
String hostnameText = hostname.getText();
|
||||
if (hostnameText == null || hostnameText.isEmpty()) {
|
||||
hostnameText = parent.getConfiguration().getHostname();
|
||||
}
|
||||
config.setHostname(hostnameText);
|
||||
config.setAutoSignIn(autoSignIn.isSelected());
|
||||
config.setUseSysTray(useSysTray.isSelected());
|
||||
// config.setUIType(GuiSwing.type);
|
||||
|
||||
|
||||
|
||||
if (saveFile.isSelected()) {
|
||||
parent.getSettingsLoader()
|
||||
.setSettings(config.getConfigFilePath(), login.getText(), new String(password.getPassword()), proxyText, hostnameText, method,
|
||||
selected_gpu, cpu_cores, max_ram, max_rendertime, getCachePath(config), getSharedPath(config), autoSignIn.isSelected(),
|
||||
useSysTray.isSelected(), headlessCheckbox.isSelected(), GuiSwing.type, themeOptionsGroup.getSelection().getActionCommand(),
|
||||
config.getPriority(), disableLargeDownloads.isSelected(), config.isDebugLevel(), incompatibleProcess.getText().trim());
|
||||
|
||||
// wait for successful authentication (to store the public key)
|
||||
// or do we already have one?
|
||||
if (parent.getClient().getServerRequest().getServerConfig() != null && parent.getClient().getServerRequest().getServerConfig().getPublickey() != null) {
|
||||
parent.getSettingsLoader().saveFile();
|
||||
sessionStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean sysTrayChanged = useSysTray.isSelected() != useSysTrayPrevState;
|
||||
boolean headlessChanged = headlessCheckbox.isSelected() != isHeadlessPrevState;
|
||||
boolean disableLargeDownloadsChanged = disableLargeDownloads.isSelected() != disableLargeDownloadsPrevState;
|
||||
boolean restartRequired = sysTrayChanged || headlessChanged || disableLargeDownloadsChanged;
|
||||
if (restartRequired) {
|
||||
String warning = "The following changes require a restart to take effect: %s";
|
||||
List<String> changes = new LinkedList<>();
|
||||
|
||||
if (sysTrayChanged) {
|
||||
changes.add("Minimize to SysTray");
|
||||
}
|
||||
|
||||
if (headlessChanged && sessionStarted) { //only show this when the setting gets changed in the middle of a session, not on launch
|
||||
changes.add("Block Eevee Projects");
|
||||
}
|
||||
|
||||
if (disableLargeDownloadsChanged && sessionStarted) {
|
||||
changes.add("Disable large Downloads");
|
||||
}
|
||||
|
||||
if (changes.isEmpty() == false) {
|
||||
warning = String.format(warning, String.join(", ", changes));
|
||||
JOptionPane.showMessageDialog(null, warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull private ComputeType getComputeType(GPUDevice selected_gpu) {
|
||||
ComputeType method = ComputeType.CPU;
|
||||
if (useCPU.isSelected() && selected_gpu == null) {
|
||||
method = ComputeType.CPU;
|
||||
}
|
||||
else if (useCPU.isSelected() == false && selected_gpu != null) {
|
||||
method = ComputeType.GPU;
|
||||
}
|
||||
else if (useCPU.isSelected() && selected_gpu != null) {
|
||||
method = ComputeType.CPU_GPU;
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
private String getCachePath(Configuration config) {
|
||||
String cachePath = null;
|
||||
if (config.isUserHasSpecifiedACacheDir() && config.getCacheDirForSettings() != null) {
|
||||
cachePath = config.getCacheDirForSettings().getAbsolutePath();
|
||||
}
|
||||
return cachePath;
|
||||
}
|
||||
|
||||
private String getSharedPath(Configuration config) {
|
||||
String sharedPath = null;
|
||||
if (config.getSharedDownloadsDirectory() != null) {
|
||||
sharedPath = config.getSharedDownloadsDirectory().getAbsolutePath();
|
||||
}
|
||||
return sharedPath;
|
||||
}
|
||||
}
|
||||
|
||||
class SaveSettingsFileAction implements ActionListener {
|
||||
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
checkDisplaySaveButton();
|
||||
}
|
||||
}
|
||||
|
||||
class JCheckBoxGPU extends JCheckBox {
|
||||
private GPUDevice gpu;
|
||||
|
||||
public JCheckBoxGPU(GPUDevice gpu) {
|
||||
super(gpu.getModel());
|
||||
this.gpu = gpu;
|
||||
}
|
||||
|
||||
public GPUDevice getGPUDevice() {
|
||||
return gpu;
|
||||
}
|
||||
}
|
||||
|
||||
public class CheckCanStart implements KeyListener {
|
||||
|
||||
@Override public void keyPressed(KeyEvent arg0) {
|
||||
}
|
||||
|
||||
@Override public void keyReleased(KeyEvent arg0) {
|
||||
checkDisplaySaveButton();
|
||||
}
|
||||
|
||||
@Override public void keyTyped(KeyEvent arg0) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
556
src/main/java/com/sheepit/client/ui/swing/activity/Working.java
Normal file
556
src/main/java/com/sheepit/client/ui/swing/activity/Working.java
Normal file
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Laurent CLOUET
|
||||
* Author Laurent CLOUET <laurent.clouet@nopnop.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui.swing.activity;
|
||||
|
||||
import java.awt.Component;
|
||||
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.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.Image;
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.UIManager;
|
||||
|
||||
import com.sheepit.client.Client;
|
||||
import com.sheepit.client.rendering.Job;
|
||||
import com.sheepit.client.logger.Log;
|
||||
import com.sheepit.client.ui.Stats;
|
||||
import com.sheepit.client.ui.TransferStats;
|
||||
import com.sheepit.client.utils.Utils;
|
||||
import com.sheepit.client.ui.GuiSwing;
|
||||
import com.sheepit.client.ui.GuiSwing.ActivityType;
|
||||
|
||||
import com.sheepit.client.ui.swing.components.CollapsibleJPanel;
|
||||
|
||||
public class Working implements Activity {
|
||||
public static final String ACTION_CLOSE_WINDOW = "Invoked close action by pressing x";
|
||||
|
||||
private GuiSwing parent;
|
||||
|
||||
private CollapsibleJPanel session_info_panel;
|
||||
private CollapsibleJPanel global_stats_panel;
|
||||
private CollapsibleJPanel last_frame_panel;
|
||||
private JLabel statusContent;
|
||||
private String previousStatus;
|
||||
private JLabel renderedFrameContent;
|
||||
private JLabel remainingFrameContent;
|
||||
private JLabel lastRenderTime;
|
||||
private JLabel lastRender;
|
||||
private JLabel creditEarned;
|
||||
private JButton pauseButton;
|
||||
private JButton exitAfterFrame;
|
||||
private JLabel current_project_name_value;
|
||||
private JLabel current_project_duration_value;
|
||||
private JLabel currrent_project_progression_value;
|
||||
private JLabel current_project_compute_method_value;
|
||||
private JLabel user_info_points_total_value;
|
||||
private JLabel renderable_projects_value;
|
||||
private JLabel waiting_projects_value;
|
||||
private JLabel connected_machines_value;
|
||||
private JLabel user_info_total_rendertime_this_session_value;
|
||||
private JLabel userInfoQueuedUploadsAndSizeValue;
|
||||
private JLabel sessionDownloadsStatsValue;
|
||||
private JLabel sessionUploadsStatsValue;
|
||||
private String currentTheme;
|
||||
private Log log;
|
||||
|
||||
public Working(GuiSwing parent_) {
|
||||
parent = parent_;
|
||||
|
||||
statusContent = new JLabel("Init");
|
||||
renderedFrameContent = new JLabel("0");
|
||||
remainingFrameContent = new JLabel("");
|
||||
creditEarned = new JLabel("");
|
||||
current_project_name_value = new JLabel("");
|
||||
current_project_duration_value = new JLabel("");
|
||||
currrent_project_progression_value = new JLabel("");
|
||||
current_project_compute_method_value = new JLabel("");
|
||||
user_info_points_total_value = new JLabel("");
|
||||
renderable_projects_value = new JLabel("");
|
||||
waiting_projects_value = new JLabel("");
|
||||
connected_machines_value = new JLabel("");
|
||||
user_info_total_rendertime_this_session_value = new JLabel("");
|
||||
lastRenderTime = new JLabel(" "); // Insert a space to ensure the component reserves the space in the screen (for the window size calculation)
|
||||
lastRender = new JLabel("");
|
||||
userInfoQueuedUploadsAndSizeValue = new JLabel("0");
|
||||
sessionDownloadsStatsValue = new JLabel("0KB");
|
||||
sessionUploadsStatsValue = new JLabel("0KB");
|
||||
currentTheme = UIManager.getLookAndFeel().getName(); // Capture the theme on component instantiation
|
||||
previousStatus = "";
|
||||
log = Log.getInstance();
|
||||
|
||||
//Overwrite the window close button behaviour to showa dialogue
|
||||
parent.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
parent.addWindowListener(new WindowAdapter() {
|
||||
@Override public void windowClosing(WindowEvent e) {
|
||||
super.windowClosing(e);
|
||||
if (parent == null || parent.getClient().isRunning() == false) {
|
||||
System.exit(0);
|
||||
}
|
||||
var exitAction = new ExitAfterAction();
|
||||
exitAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, ACTION_CLOSE_WINDOW));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override public void show() {
|
||||
// If the stored theme and the UIManager's theme doesn't match is bc the user has changed it
|
||||
if (!currentTheme.equals(UIManager.getLookAndFeel().getName())) {
|
||||
// And, as the user has changed the theme, then we must recreate all the UI elements with session data
|
||||
// Reason being they are defined as class variables and therefore created once when the object
|
||||
// is created the first time.
|
||||
// As the Java swing engine applies the "look & feel" at creation time, we need to "re-create" the
|
||||
// objects to ensure they have the right theme colors.
|
||||
statusContent = new JLabel(statusContent.getText());
|
||||
renderedFrameContent = new JLabel(renderedFrameContent.getText());
|
||||
remainingFrameContent = new JLabel(remainingFrameContent.getText());
|
||||
creditEarned = new JLabel(creditEarned.getText());
|
||||
current_project_name_value = new JLabel(current_project_name_value.getText());
|
||||
current_project_duration_value = new JLabel(current_project_duration_value.getText());
|
||||
currrent_project_progression_value = new JLabel(currrent_project_progression_value.getText());
|
||||
current_project_compute_method_value = new JLabel(current_project_compute_method_value.getText());
|
||||
user_info_points_total_value = new JLabel(user_info_points_total_value.getText());
|
||||
renderable_projects_value = new JLabel(renderable_projects_value.getText());
|
||||
waiting_projects_value = new JLabel(waiting_projects_value.getText());
|
||||
connected_machines_value = new JLabel(connected_machines_value.getText());
|
||||
user_info_total_rendertime_this_session_value = new JLabel(user_info_total_rendertime_this_session_value.getText());
|
||||
lastRenderTime = new JLabel(lastRenderTime.getText());
|
||||
lastRender = new JLabel(lastRender.getText());
|
||||
userInfoQueuedUploadsAndSizeValue = new JLabel(userInfoQueuedUploadsAndSizeValue.getText());
|
||||
sessionDownloadsStatsValue = new JLabel(sessionDownloadsStatsValue.getText());
|
||||
sessionUploadsStatsValue = new JLabel(sessionUploadsStatsValue.getText());
|
||||
|
||||
// set the new theme as the current one
|
||||
currentTheme = UIManager.getLookAndFeel().getName();
|
||||
}
|
||||
|
||||
// current project
|
||||
JPanel current_project_panel = new JPanel(new GridLayout(5, 2));
|
||||
current_project_panel.setBorder(BorderFactory.createTitledBorder("Project"));
|
||||
|
||||
JLabel current_project_status = new JLabel("Status: ", JLabel.TRAILING);
|
||||
JLabel current_project_name = new JLabel("Name: ", JLabel.TRAILING);
|
||||
JLabel current_project_duration = new JLabel("Rendering for: ", JLabel.TRAILING);
|
||||
JLabel current_project_progression = new JLabel("Remaining: ", JLabel.TRAILING);
|
||||
JLabel current_project_compute_method_label = new JLabel("Compute method: ", JLabel.TRAILING);
|
||||
|
||||
current_project_panel.add(current_project_status);
|
||||
current_project_panel.add(statusContent);
|
||||
|
||||
current_project_panel.add(current_project_name);
|
||||
current_project_panel.add(current_project_name_value);
|
||||
|
||||
current_project_panel.add(current_project_duration);
|
||||
current_project_panel.add(current_project_duration_value);
|
||||
|
||||
current_project_panel.add(current_project_progression);
|
||||
current_project_panel.add(currrent_project_progression_value);
|
||||
|
||||
current_project_panel.add(current_project_compute_method_label);
|
||||
current_project_panel.add(current_project_compute_method_value);
|
||||
|
||||
// user info
|
||||
session_info_panel = new CollapsibleJPanel(new GridLayout(7, 2), this);
|
||||
session_info_panel.setBorder(BorderFactory.createTitledBorder("Session infos"));
|
||||
|
||||
JLabel user_info_credits_this_session = new JLabel("Points earned: ", JLabel.TRAILING);
|
||||
JLabel user_info_total_rendertime_this_session = new JLabel("Duration: ", JLabel.TRAILING);
|
||||
JLabel user_info_pending_uploads_and_size = new JLabel("Queued uploads: ", JLabel.TRAILING);
|
||||
JLabel session_download_stats = new JLabel("Total Downloads: ", JLabel.TRAILING);
|
||||
JLabel session_upload_stats = new JLabel("Total Uploads: ", JLabel.TRAILING);
|
||||
JLabel user_info_rendered_frame_this_session = new JLabel("Rendered frames: ", JLabel.TRAILING);
|
||||
JLabel global_static_renderable_project = new JLabel("Renderable projects: ", JLabel.TRAILING);
|
||||
|
||||
session_info_panel.add(user_info_credits_this_session);
|
||||
session_info_panel.add(creditEarned);
|
||||
|
||||
session_info_panel.add(user_info_rendered_frame_this_session);
|
||||
session_info_panel.add(renderedFrameContent);
|
||||
|
||||
session_info_panel.add(user_info_pending_uploads_and_size);
|
||||
session_info_panel.add(userInfoQueuedUploadsAndSizeValue);
|
||||
|
||||
session_info_panel.add(session_download_stats);
|
||||
session_info_panel.add(sessionDownloadsStatsValue);
|
||||
|
||||
session_info_panel.add(session_upload_stats);
|
||||
session_info_panel.add(sessionUploadsStatsValue);
|
||||
|
||||
session_info_panel.add(global_static_renderable_project);
|
||||
session_info_panel.add(renderable_projects_value);
|
||||
|
||||
session_info_panel.add(user_info_total_rendertime_this_session);
|
||||
session_info_panel.add(user_info_total_rendertime_this_session_value);
|
||||
|
||||
// global stats
|
||||
global_stats_panel = new CollapsibleJPanel(new GridLayout(4, 2), this);
|
||||
global_stats_panel.setBorder(BorderFactory.createTitledBorder("Global stats"));
|
||||
|
||||
JLabel global_stats_machine_connected = new JLabel("Machines connected: ", JLabel.TRAILING);
|
||||
JLabel global_stats_remaining_frame = new JLabel("Remaining frames: ", JLabel.TRAILING);
|
||||
JLabel global_stats_waiting_project = new JLabel("Active projects: ", JLabel.TRAILING);
|
||||
JLabel global_stats_user_points = new JLabel("User's points: ", JLabel.TRAILING);
|
||||
|
||||
global_stats_panel.add(global_stats_waiting_project);
|
||||
global_stats_panel.add(waiting_projects_value);
|
||||
|
||||
global_stats_panel.add(global_stats_machine_connected);
|
||||
global_stats_panel.add(connected_machines_value);
|
||||
|
||||
global_stats_panel.add(global_stats_remaining_frame);
|
||||
global_stats_panel.add(remainingFrameContent);
|
||||
|
||||
global_stats_panel.add(global_stats_user_points);
|
||||
global_stats_panel.add(user_info_points_total_value);
|
||||
|
||||
// last frame
|
||||
last_frame_panel = new CollapsibleJPanel(new GridLayout(2, 2), this);
|
||||
last_frame_panel.setLayout(new BoxLayout(last_frame_panel, BoxLayout.Y_AXIS));
|
||||
last_frame_panel.setBorder(BorderFactory.createTitledBorder("Last uploaded frame"));
|
||||
lastRender.setIcon(new ImageIcon(new BufferedImage(200, 120, BufferedImage.TYPE_INT_ARGB)));
|
||||
lastRender.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||
lastRenderTime.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||
last_frame_panel.add(lastRenderTime);
|
||||
last_frame_panel.add(lastRender);
|
||||
|
||||
JLabel labelImage = GuiSwing.createLogoWithWatermark();
|
||||
labelImage.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||
parent.getContentPanel().add(labelImage);
|
||||
|
||||
JPanel buttonsPanel = new JPanel(new GridLayout(2, 2));
|
||||
|
||||
JButton settingsButton = new JButton("Settings");
|
||||
settingsButton.addActionListener(new SettingsAction());
|
||||
|
||||
pauseButton = new JButton("Pause getting new jobs");
|
||||
Client client = parent.getClient();
|
||||
if (client != null && client.isSuspended()) {
|
||||
pauseButton.setText("Resume getting jobs");
|
||||
}
|
||||
|
||||
pauseButton.addActionListener(new PauseAction());
|
||||
|
||||
JButton blockJob = new JButton("Block this project");
|
||||
blockJob.addActionListener(new blockJobAction());
|
||||
|
||||
exitAfterFrame = new JButton("Exit");
|
||||
ExitAfterAction exitAfterAction = new ExitAfterAction();
|
||||
exitAfterFrame.addActionListener(exitAfterAction);
|
||||
if (client != null && client.isAwaitingStop()) {
|
||||
exitAfterAction.finishJobBeforeExit(client, getJobsQueueSize(client));
|
||||
}
|
||||
|
||||
buttonsPanel.add(settingsButton);
|
||||
buttonsPanel.add(pauseButton);
|
||||
buttonsPanel.add(blockJob);
|
||||
buttonsPanel.add(exitAfterFrame);
|
||||
|
||||
parent.getContentPanel().setLayout(new GridBagLayout());
|
||||
GridBagConstraints global_constraints = new GridBagConstraints();
|
||||
global_constraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
global_constraints.weightx = 1;
|
||||
global_constraints.gridx = 0;
|
||||
|
||||
parent.getContentPanel().add(new JLabel(" "), global_constraints); // Add a separator between logo and first panel
|
||||
parent.getContentPanel().add(current_project_panel, global_constraints);
|
||||
parent.getContentPanel().add(global_stats_panel, global_constraints);
|
||||
parent.getContentPanel().add(session_info_panel, global_constraints);
|
||||
parent.getContentPanel().add(last_frame_panel, global_constraints);
|
||||
parent.getContentPanel().add(new JLabel(" "), global_constraints); // Add a separator between last panel and buttons
|
||||
parent.getContentPanel().add(buttonsPanel, global_constraints);
|
||||
|
||||
// Set the proper size for the Working (if coming from Settings screen, the window size will be too big for the content!)
|
||||
parent.setSize(GuiSwing.WIDTH, 820);
|
||||
}
|
||||
|
||||
@Override public void resizeWindow() {
|
||||
parent.revalidate();
|
||||
parent.repaint();
|
||||
}
|
||||
|
||||
public void setStatus(String msg_) {
|
||||
setStatus(msg_, false);
|
||||
}
|
||||
|
||||
public void setStatus(String msg_, boolean overwriteSuspendedMsg) {
|
||||
Client client = parent.getClient();
|
||||
|
||||
if ("".equals(msg_) == false) {
|
||||
this.previousStatus = msg_;
|
||||
}
|
||||
|
||||
if (client != null && client.isSuspended()) {
|
||||
if (overwriteSuspendedMsg) {
|
||||
statusContent.setText("<html>" + msg_ + "</html>");
|
||||
}
|
||||
}
|
||||
else {
|
||||
statusContent.setText("<html>" + msg_ + "</html>");
|
||||
}
|
||||
}
|
||||
|
||||
public void setRenderingProjectName(String msg_) {
|
||||
current_project_name_value.setText("<html>" + (msg_.length() > 26 ? msg_.substring(0, 26) : msg_) + "</html>");
|
||||
}
|
||||
|
||||
public void setRemainingTime(String time_) {
|
||||
currrent_project_progression_value.setText("<html>" + time_ + "</html>");
|
||||
}
|
||||
|
||||
public void setRenderingTime(String time_) {
|
||||
current_project_duration_value.setText("<html>" + time_ + "</html>");
|
||||
}
|
||||
|
||||
public void setComputeMethod(String computeMethod_) {
|
||||
this.current_project_compute_method_value.setText(computeMethod_);
|
||||
}
|
||||
|
||||
public void displayTransferStats(TransferStats downloads, TransferStats uploads) {
|
||||
sessionDownloadsStatsValue.setText(String.format("%s @ %s/s", downloads.getSessionTraffic(), downloads.getAverageSessionSpeed()));
|
||||
sessionUploadsStatsValue.setText(String.format("%s @ %s/s", uploads.getSessionTraffic(), uploads.getAverageSessionSpeed()));
|
||||
updateTime();
|
||||
}
|
||||
|
||||
public void displayStats(Stats stats) {
|
||||
DecimalFormat df = new DecimalFormat("##,##,##,##,##,##,##0");
|
||||
remainingFrameContent.setText(df.format(stats.getRemainingFrame()));
|
||||
creditEarned.setText(df.format(stats.getCreditsEarnedSession()));
|
||||
user_info_points_total_value.setText(df.format(stats.getCreditsEarned()));
|
||||
renderable_projects_value.setText(df.format(stats.getRenderableProject()));
|
||||
waiting_projects_value.setText(df.format(stats.getWaitingProject()));
|
||||
connected_machines_value.setText(df.format(stats.getConnectedMachine()));
|
||||
|
||||
updateTime();
|
||||
}
|
||||
|
||||
public void displayUploadQueueStats(int queueSize, long queueVolume) {
|
||||
userInfoQueuedUploadsAndSizeValue.setText(
|
||||
String.format("%d%s%s", queueSize, (queueSize > 0 ? String.format(" (%.2fMB) ", (queueVolume / 1024.0 / 1024.0)) : ""),
|
||||
(queueSize == this.parent.getConfiguration().getMaxUploadingJob() ? "- Queue full!" : "")));
|
||||
|
||||
// If the user has requested to exit, then we need to update the JButton with the queue size
|
||||
if (this.exitAfterFrame.getText().startsWith("Cancel")) {
|
||||
Client client = parent.getClient();
|
||||
|
||||
if (client != null && client.isRunning()) {
|
||||
queueSize++;
|
||||
}
|
||||
|
||||
exitAfterFrame.setText(String.format("Cancel exit (%s frame%s to go)", queueSize, (queueSize > 1 ? "s" : "")));
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void updateTime() {
|
||||
if (this.parent.getClient().getStartTime() != 0) {
|
||||
user_info_total_rendertime_this_session_value
|
||||
.setText(Utils.humanDuration(new Date((new Date().getTime() - this.parent.getClient().getStartTime()))));
|
||||
}
|
||||
Job job = this.parent.getClient().getRenderingJob();
|
||||
if (job != null && job.getProcessRender() != null && job.getProcessRender().getStartTime() > 0) {
|
||||
current_project_duration_value
|
||||
.setText("<html>" + Utils.humanDuration(new Date((new Date().getTime() - job.getProcessRender().getStartTime()))) + "</html>");
|
||||
}
|
||||
else {
|
||||
current_project_duration_value.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
public void setRenderedFrame(int n) {
|
||||
renderedFrameContent.setText(String.valueOf(n));
|
||||
showLastRender();
|
||||
}
|
||||
|
||||
public void showLastRender() {
|
||||
Client client = parent.getClient();
|
||||
if (client != null) {
|
||||
Job lastJob = client.getPreviousJob();
|
||||
if (lastJob != null) {
|
||||
ImageIcon icon = null;
|
||||
int idInt = Integer.parseInt(lastJob.getId());
|
||||
if (idInt == 1) {
|
||||
icon = new ImageIcon(getClass().getResource("/frame_compute_method.jpg"));
|
||||
}
|
||||
else if (idInt < 20) {
|
||||
icon = new ImageIcon(getClass().getResource("/frame_power_detection.jpg"));
|
||||
}
|
||||
else {
|
||||
String path = null;
|
||||
try {
|
||||
boolean hasPreview = lastJob.getRenderOutput().getPreviewImagePath() != null;
|
||||
|
||||
if (hasPreview) {
|
||||
path = lastJob.getRenderOutput().getPreviewImagePath();
|
||||
}
|
||||
else {
|
||||
path = lastJob.getRenderOutput().getFullImagePath();
|
||||
}
|
||||
|
||||
BufferedImage img = ImageIO.read(new File(path));
|
||||
float width = img.getWidth();
|
||||
float height = img.getHeight();
|
||||
float factor = 1.0f;
|
||||
if (height > 200) {
|
||||
factor = 200f / height;
|
||||
}
|
||||
if (width * factor > 200) {
|
||||
factor = Math.min(factor, 200f / width);
|
||||
}
|
||||
icon = new ImageIcon(img.getScaledInstance((int) (width * factor), (int) (height * factor), Image.SCALE_FAST));
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(String.format("Working::showLastRender() Unable to load/preview rendered frame [%s]. Exception %s",
|
||||
path, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
if (icon != null) {
|
||||
lastRender.setIcon(icon);
|
||||
// don't use lastJob.getProcessRender().getDuration() due to timezone
|
||||
if (lastJob.getProcessRender().getDuration() > 1) {
|
||||
lastRenderTime.setText(
|
||||
"Render time : " + Utils.humanDuration(new Date(lastJob.getProcessRender().getRenderDuration() * 1000L))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int getJobsQueueSize(Client client) {
|
||||
return client.getUploadQueueSize() + (client.getRenderingJob() != null ? 1 : 0);
|
||||
}
|
||||
|
||||
class PauseAction implements ActionListener {
|
||||
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
Client client = parent.getClient();
|
||||
if (client != null) {
|
||||
if (client.isSuspended()) {
|
||||
pauseButton.setText("Pause getting new jobs");
|
||||
client.resume();
|
||||
setStatus(previousStatus);
|
||||
}
|
||||
else {
|
||||
pauseButton.setText("Resume getting jobs");
|
||||
client.suspend();
|
||||
setStatus("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsAction implements ActionListener {
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
if (parent != null) {
|
||||
parent.showActivity(ActivityType.SETTINGS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExitAfterAction implements ActionListener {
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
Client client = parent.getClient();
|
||||
if (client != null) {
|
||||
if (client.isRunning() == false && Objects.equals(e.getActionCommand(), ACTION_CLOSE_WINDOW) == false) {
|
||||
cancelExit(client);
|
||||
return;
|
||||
}
|
||||
|
||||
int jobsQueueSize = getJobsQueueSize(client);
|
||||
if (jobsQueueSize == 0) {
|
||||
int userDecision = showCloseDialogNoFrame();
|
||||
if (userDecision == 0) {
|
||||
exitImmediately(client);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int userDecision = showCloseDialog(jobsQueueSize);
|
||||
if (userDecision == 0) {
|
||||
finishJobBeforeExit(client, jobsQueueSize);
|
||||
}
|
||||
else if (userDecision == 1) {
|
||||
exitImmediately(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int showCloseDialogNoFrame() {
|
||||
String[] exitJobOptions = {"Exit Immediately", "Do Nothing" };
|
||||
return JOptionPane.showOptionDialog(null, "Exit Now or Later", "Exit Now or Later",
|
||||
JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, exitJobOptions, exitJobOptions[1]); // Make the "Do nothing" button the default one to avoid mistakes
|
||||
}
|
||||
|
||||
public int showCloseDialog(int jobsQueueSize) {
|
||||
String[] exitJobOptions = { "Exit after current Jobs", "Exit Immediately", "Do Nothing" };
|
||||
return JOptionPane.showOptionDialog(null, String.format(
|
||||
"<html>You have <strong>%d frame%s</strong> being uploaded or rendered. Do you want to finish the jobs or exit now?.\n\n",
|
||||
jobsQueueSize, // Add the current frame to the total count ONLY if the client is running
|
||||
(jobsQueueSize > 1 ? "s" : ""), (jobsQueueSize > 1 ? (jobsQueueSize + " ") : ""), (jobsQueueSize > 1 ? "s" : "")),
|
||||
"Exit Now or Later", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, exitJobOptions,
|
||||
exitJobOptions[2]); // Make the "Do nothing" button the default one to avoid mistakes
|
||||
}
|
||||
|
||||
public void finishJobBeforeExit(Client client, int jobsQueueSize) {
|
||||
exitAfterFrame.setText(String.format("Cancel exit (%s frame%s to go)", jobsQueueSize, (jobsQueueSize > 1 ? "s" : "")));
|
||||
client.askForStop();
|
||||
}
|
||||
|
||||
public void exitImmediately(Client client) {
|
||||
client.stop();
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public void cancelExit(Client client) {
|
||||
exitAfterFrame.setText("Exit");
|
||||
client.cancelStop();
|
||||
}
|
||||
}
|
||||
|
||||
class blockJobAction implements ActionListener {
|
||||
@Override public void actionPerformed(ActionEvent e) {
|
||||
Client client = parent.getClient();
|
||||
if (client != null) {
|
||||
Job job = client.getRenderingJob();
|
||||
if (job != null) {
|
||||
job.block();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Laurent CLOUET
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
package com.sheepit.client.ui.swing.components;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.BorderFactory;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.TitledBorder;
|
||||
|
||||
import com.sheepit.client.ui.swing.activity.Activity;
|
||||
|
||||
public class CollapsibleJPanel extends JPanel {
|
||||
|
||||
private boolean isCompnentsVisible = true;
|
||||
private int originalHeight;
|
||||
private String borderTitle = "";
|
||||
private int COLLAPSED_HEIGHT = 22;
|
||||
private boolean[] originalVisibilty;
|
||||
private Activity parent;
|
||||
|
||||
public CollapsibleJPanel(LayoutManager layoutManager, Activity parent) {
|
||||
setLayout(layoutManager);
|
||||
addMouseListener(new onClickHandler());
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void setCollapsed(boolean aFlag) {
|
||||
if (aFlag) {
|
||||
hideComponents();
|
||||
}
|
||||
else {
|
||||
showComponents();
|
||||
}
|
||||
}
|
||||
|
||||
public void toggleCollapsed() {
|
||||
if (isCompnentsVisible) {
|
||||
setCollapsed(true);
|
||||
}
|
||||
else {
|
||||
setCollapsed(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void hideComponents() {
|
||||
|
||||
Component[] components = getComponents();
|
||||
|
||||
originalVisibilty = new boolean[components.length];
|
||||
|
||||
// Hide all componens on panel
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
originalVisibilty[i] = components[i].isVisible();
|
||||
components[i].setVisible(false);
|
||||
}
|
||||
|
||||
setHeight(COLLAPSED_HEIGHT);
|
||||
|
||||
// Add '+' char to end of border title
|
||||
//setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), borderTitle + " + "));
|
||||
setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), " + " + borderTitle));
|
||||
|
||||
// Update flag
|
||||
isCompnentsVisible = false;
|
||||
}
|
||||
|
||||
private void showComponents() {
|
||||
|
||||
Component[] components = getComponents();
|
||||
|
||||
// Set all components in panel to visible
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
components[i].setVisible(originalVisibilty[i]);
|
||||
}
|
||||
|
||||
setHeight(originalHeight);
|
||||
|
||||
// Add '-' char to end of border title
|
||||
setBorder(BorderFactory.createTitledBorder(" - " + borderTitle));
|
||||
|
||||
// Update flag
|
||||
isCompnentsVisible = true;
|
||||
}
|
||||
|
||||
private void setHeight(int height) {
|
||||
setPreferredSize(new Dimension(getPreferredSize().width, height));
|
||||
setMinimumSize(new Dimension(getMinimumSize().width, height));
|
||||
setMaximumSize(new Dimension(getMaximumSize().width, height));
|
||||
}
|
||||
|
||||
@Override public Component add(Component component) { // Need this to get the original height of panel
|
||||
|
||||
Component returnComponent = super.add(component);
|
||||
|
||||
originalHeight = getPreferredSize().height;
|
||||
|
||||
return returnComponent;
|
||||
}
|
||||
|
||||
@Override public void setBorder(Border border) { // Need this to get the border title
|
||||
|
||||
if (border instanceof TitledBorder && (borderTitle == "")) {
|
||||
borderTitle = ((TitledBorder) border).getTitle();
|
||||
|
||||
((TitledBorder) border).setTitle(" - " + borderTitle);
|
||||
}
|
||||
|
||||
super.setBorder(border);
|
||||
}
|
||||
|
||||
public class onClickHandler implements MouseListener {
|
||||
|
||||
@Override public void mouseClicked(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override public void mousePressed(MouseEvent e) {
|
||||
if (e.getPoint().y < COLLAPSED_HEIGHT) { // Only if click is on top of panel
|
||||
((CollapsibleJPanel) e.getComponent()).toggleCollapsed();
|
||||
}
|
||||
|
||||
// Recalculate the proper window size
|
||||
parent.resizeWindow();
|
||||
}
|
||||
|
||||
@Override public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override public void mouseExited(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override public void mouseReleased(MouseEvent e) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Laurent CLOUET
|
||||
* Author Rolf Aretz Lap <rolf.aretz@ottogroup.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui.text;
|
||||
|
||||
import com.sheepit.client.Client;
|
||||
import com.sheepit.client.config.Configuration;
|
||||
import com.sheepit.client.rendering.Job;
|
||||
|
||||
public class CLIInputActionHandler implements CLIInputListener {
|
||||
|
||||
@Override public void commandEntered(Client client, String command) {
|
||||
int priorityLength = "priority".length();
|
||||
|
||||
//prevent Null Pointer at next step
|
||||
if (command == null) {
|
||||
return;
|
||||
}
|
||||
if (client == null) {
|
||||
return;
|
||||
}
|
||||
if ("block".equalsIgnoreCase(command)) {
|
||||
Job job = client.getRenderingJob();
|
||||
if (job != null) {
|
||||
job.block();
|
||||
}
|
||||
}
|
||||
else if ("resume".equalsIgnoreCase(command)) {
|
||||
client.resume();
|
||||
}
|
||||
else if ("pause".equalsIgnoreCase(command)) {
|
||||
client.suspend();
|
||||
}
|
||||
else if ("stop".equalsIgnoreCase(command)) {
|
||||
client.askForStop();
|
||||
}
|
||||
else if ("status".equalsIgnoreCase(command)) {
|
||||
displayStatus(client);
|
||||
}
|
||||
else if ("cancel".equalsIgnoreCase(command)) {
|
||||
client.cancelStop();
|
||||
}
|
||||
else if ("quit".equalsIgnoreCase(command)) {
|
||||
client.stop();
|
||||
System.exit(0);
|
||||
}
|
||||
else if ((command.length() > priorityLength) && "priority".equalsIgnoreCase(command.substring(0, priorityLength))) {
|
||||
changePriority(client, command.substring(priorityLength));
|
||||
}
|
||||
else {
|
||||
System.out.println("Unknown command: " + command);
|
||||
System.out.println("status: display client status");
|
||||
System.out.println("priority <n>: set the priority for the next renderjob");
|
||||
System.out.println("block: block project");
|
||||
System.out.println("pause: pause client requesting new jobs");
|
||||
System.out.println("resume: resume after client was paused");
|
||||
System.out.println("stop: exit after frame was finished");
|
||||
System.out.println("cancel: cancel exit");
|
||||
System.out.println("quit: exit now");
|
||||
}
|
||||
}
|
||||
|
||||
void changePriority(Client client, String newPriority) {
|
||||
Configuration config = client.getConfiguration();
|
||||
if (config != null) {
|
||||
try {
|
||||
config.setPriority(Integer.parseInt(newPriority.trim()));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.out.println("Invalid priority: " + newPriority);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void displayStatus(Client client) {
|
||||
if (client.isSuspended()) {
|
||||
System.out.println("Status: paused");
|
||||
}
|
||||
else if (client.isRunning()) {
|
||||
System.out.println("Status: running");
|
||||
}
|
||||
else {
|
||||
System.out.println("Status: will exit after the current frame");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Laurent CLOUET
|
||||
* Author Rolf Aretz Lap <rolf.aretz@ottogroup.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui.text;
|
||||
|
||||
import com.sheepit.client.Client;
|
||||
|
||||
public interface CLIInputListener {
|
||||
public void commandEntered(Client client, String command);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Laurent CLOUET
|
||||
* Author Rolf Aretz Lap <rolf.aretz@ottogroup.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package com.sheepit.client.ui.text;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sheepit.client.Client;
|
||||
|
||||
public class CLIInputObserver implements Runnable {
|
||||
private BufferedReader in;
|
||||
private Client client;
|
||||
|
||||
public CLIInputObserver(Client client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
private List<CLIInputListener> listeners = new ArrayList<CLIInputListener>();
|
||||
|
||||
public void addListener(CLIInputListener toAdd) {
|
||||
listeners.add(toAdd);
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
in = new BufferedReader(new InputStreamReader(System.in));
|
||||
String line = "";
|
||||
|
||||
while ((line != null) && ("quit".equalsIgnoreCase(line) == false)) {
|
||||
try {
|
||||
line = in.readLine();
|
||||
}
|
||||
catch (IOException e) {
|
||||
// if the program has been launched into the background (e.g. with nohup), input is not valid
|
||||
client.getLog().info("Unable to read user input, ignoring all further inputs");
|
||||
break;
|
||||
}
|
||||
for (CLIInputListener cliil : listeners)
|
||||
cliil.commandEntered(client, line);
|
||||
}
|
||||
try {
|
||||
in.close();
|
||||
}
|
||||
catch (Exception e) {
|
||||
// TODO: handle exception
|
||||
client.getLog().error("FIXME: Unhandled exception while closing InputStreamReader(): " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user