The text UI gets quite messy during the render process, as it takes at least one extra line of the screen per second. This PR fixes that issue and also shows an ASCII bar to show the render progress.
418 lines
11 KiB
Java
418 lines
11 KiB
Java
/*
|
|
* 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.standalone;
|
|
|
|
import java.awt.AWTException;
|
|
import java.awt.GridBagLayout;
|
|
import java.awt.Image;
|
|
import java.awt.MenuItem;
|
|
import java.awt.PopupMenu;
|
|
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.net.URL;
|
|
import java.util.Timer;
|
|
import java.util.TimerTask;
|
|
|
|
import java.io.IOException;
|
|
|
|
import javax.swing.ImageIcon;
|
|
import javax.swing.JFrame;
|
|
import javax.swing.JPanel;
|
|
import javax.swing.UIManager;
|
|
import javax.swing.UnsupportedLookAndFeelException;
|
|
import javax.swing.border.EmptyBorder;
|
|
import javax.imageio.ImageIO;
|
|
|
|
import com.sheepit.client.Client;
|
|
import com.sheepit.client.Configuration;
|
|
import com.sheepit.client.Gui;
|
|
import com.sheepit.client.SettingsLoader;
|
|
import com.sheepit.client.Stats;
|
|
import com.sheepit.client.standalone.swing.activity.Settings;
|
|
import com.sheepit.client.standalone.swing.activity.Working;
|
|
import lombok.Getter;
|
|
import lombok.Setter;
|
|
|
|
import com.formdev.flatlaf.FlatLightLaf; // Required for dark & light mode
|
|
import com.formdev.flatlaf.FlatDarkLaf;
|
|
import com.formdev.flatlaf.FlatLaf;
|
|
|
|
public class GuiSwing extends JFrame implements Gui {
|
|
public static final String type = "swing";
|
|
|
|
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 BufferedImage iconSprites;
|
|
private BufferedImage[] trayIconSprites;
|
|
|
|
@Getter @Setter private SettingsLoader settingsLoader;
|
|
|
|
private ThreadClient threadClient;
|
|
|
|
public GuiSwing(boolean useSysTray_, String title_) {
|
|
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() {
|
|
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);
|
|
trayIconSprites = new BufferedImage[101 * 1]; // sprite sheet has 101 images in 1 column
|
|
|
|
setIconImage(extractImageFromSprite(-1)); // sprite 0 is standard Sheep It! icon
|
|
}
|
|
catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
setTitle(title);
|
|
setSize(520, 760);
|
|
|
|
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
|
|
|
panel = new JPanel();
|
|
panel.setLayout(new GridBagLayout());
|
|
setContentPane(this.panel);
|
|
panel.setBorder(new EmptyBorder(20, 20, 20, 20));
|
|
|
|
activityWorking = new Working(this);
|
|
activitySettings = new Settings(this);
|
|
|
|
this.showActivity(ActivityType.SETTINGS);
|
|
|
|
try {
|
|
if (client.getConfiguration().getTheme().equals("light")) {
|
|
UIManager.setLookAndFeel(new FlatLightLaf());
|
|
}
|
|
else if (client.getConfiguration().getTheme().equals("dark")) {
|
|
UIManager.setLookAndFeel(new FlatDarkLaf());
|
|
}
|
|
|
|
// Apply the selected theme to swing components
|
|
FlatLaf.updateUI();
|
|
}
|
|
catch (UnsupportedLookAndFeelException e1) {
|
|
e1.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 status(String msg, int progress, long size) {
|
|
this.status(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 void AddFrameRendered() {
|
|
framesRendered++;
|
|
|
|
if (activityWorking != null) {
|
|
this.activityWorking.setRenderedFrame(framesRendered);
|
|
}
|
|
else {
|
|
System.out.println("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 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.setPassword(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) {
|
|
System.out.println("GuiSwing::hideToTray SystemTray not supported!");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
trayIcon = getTrayIcon();
|
|
sysTray.add(trayIcon);
|
|
}
|
|
catch (AWTException e) {
|
|
System.out.println("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() & ~JFrame.ICONIFIED & JFrame.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;
|
|
|
|
}
|
|
|
|
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()) {
|
|
if (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();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|