package org.openslx.dozmod.gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import org.apache.log4j.Logger;
import org.apache.thrift.TException;
import org.openslx.bwlp.thrift.iface.SatelliteStatus;
import org.openslx.bwlp.thrift.iface.WhoamiInfo;
import org.openslx.dozmod.App;
import org.openslx.dozmod.Config;
import org.openslx.dozmod.Config.SavedSession;
import org.openslx.dozmod.filetransfer.DownloadTask;
import org.openslx.dozmod.gui.Gui.GuiCallable;
import org.openslx.dozmod.gui.activity.ActivityPanel;
import org.openslx.dozmod.gui.activity.DownloadPanel;
import org.openslx.dozmod.gui.activity.UploadPanel;
import org.openslx.dozmod.gui.helper.CompositePage;
import org.openslx.dozmod.gui.helper.DebugWindow;
import org.openslx.dozmod.gui.helper.MessageType;
import org.openslx.dozmod.gui.helper.UiFeedback;
import org.openslx.dozmod.gui.window.DisclaimerWindow;
import org.openslx.dozmod.gui.window.ImageListWindow;
import org.openslx.dozmod.gui.window.LectureListWindow;
import org.openslx.dozmod.gui.window.LoginWindow;
import org.openslx.dozmod.gui.window.MainMenuWindow;
import org.openslx.dozmod.gui.window.VirtualizerNoticeWindow;
import org.openslx.dozmod.state.UploadWizardState;
import org.openslx.dozmod.thrift.GuiErrorCallback;
import org.openslx.dozmod.thrift.Session;
import org.openslx.dozmod.util.FormatHelper;
import org.openslx.thrifthelper.ThriftManager;
import org.openslx.util.QuickTimer;
import org.openslx.util.QuickTimer.Task;
public abstract class MainWindow {
private final static Logger LOGGER = Logger.getLogger(MainWindow.class);
private static final JFrame mainWindow;
private static final JPanel mainContainer;
private static final JPanel activityPanel;
private static CompositePage currentPage;
private static boolean isQuitQuestionOpen = false;
private static final Map<Class<? extends CompositePage>, CompositePage> pages = new ConcurrentHashMap<>();
private static final List<ActivityPanel> activities = new ArrayList<>();
/**
* Set the visible page of the main window.
*
* @param clazz
*/
public static void showPage(Class<? extends CompositePage> clazz) {
if (currentPage != null) {
if (!currentPage.requestHide()) {
return; // Canceled by currently shown page
}
currentPage.setVisible(false);
}
currentPage = pages.get(clazz);
if (currentPage == null) {
Gui.showMessageBox(mainWindow, "Tried to show unknown page " + clazz.getSimpleName(),
MessageType.ERROR, LOGGER, null);
Gui.exit(1);
return;
}
// sets the starting preferred size.
currentPage.requestShow();
currentPage.setVisible(true);
mainWindow.validate();
}
public static void centerShell(Window shell) {
Gui.centerShellOverShell(mainWindow, shell);
}
static {
mainWindow = Gui.syncExec(new GuiCallable<JFrame>() {
@Override
public JFrame run() {
return new JFrame("bwLehrstuhl");
}
});
mainContainer = Gui.syncExec(new GuiCallable<JPanel>() {
@Override
public JPanel run() {
return new JPanel();
}
});
activityPanel = Gui.syncExec(new GuiCallable<JPanel>() {
@Override
public JPanel run() {
return new JPanel();
}
});
}
/**
* Initializes the GUI by creating the main window, adding the menu and
* creating the login mask as the first content window.
* Further sets up the global thrift error callback to catch any
* connection errors during the communication with the servers.
*/
public static void open() {
// init SWT stuff
mainWindow.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
// Catch the close button (X)
mainWindow.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
MainWindow.askApplicationQuit();
}
});
// Set up thrift error message displaying
ThriftManager.setMasterErrorCallback(new GuiErrorCallback(mainWindow, "dem bwLehrpool-Zentralserver"));
ThriftManager.setSatelliteErrorCallback(new GuiErrorCallback(mainWindow, "dem Satellitenserver"));
// Same for config errors
Config.setErrorCallback(new Config.ErrorCallback() {
@Override
public void writeError(final Throwable t) {
Gui.asyncExec(new Runnable() {
@Override
public void run() {
Gui.showMessageBox(mainWindow, "Konnte Programmeinstellungen nicht speichern",
MessageType.WARNING, LOGGER, t);
}
});
}
});
// Global key listener
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int type = event.getID();
int code = event.getKeyChar();
if (code == 17) { // Ctrl-Q = Quit
if (type == KeyEvent.KEY_RELEASED && !isQuitQuestionOpen) {
isQuitQuestionOpen = true;
askApplicationQuit();
}
event.consume();
} else if (code == 27 || code == 23) { // ESC or Ctrl-W closes current window
if (type == KeyEvent.KEY_PRESSED) {
Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager()
.getActiveWindow();
if (window instanceof UiFeedback) {
((UiFeedback) window).escapePressed();
}
}
event.consume();
}
return event.isConsumed();
}
});
createMenu();
// Set layout for the mainshell, items added to the shell should get a gridData
mainContainer.setLayout(new BoxLayout(mainContainer, BoxLayout.PAGE_AXIS));
mainWindow.setMinimumSize(new Dimension(850, 650));
// register all pages of the main window
registerPage(new MainMenuWindow());
registerPage(new ImageListWindow());
registerPage(new LectureListWindow());
// Debug?
if (System.getProperty("log") != null) {
DebugWindow win = new DebugWindow();
win.setMinimumSize(new Dimension(0, 250));
win.setPreferredSize(win.getMinimumSize());
mainWindow.getContentPane().add(win, BorderLayout.PAGE_START);
}
activityPanel.setLayout(new BoxLayout(activityPanel, BoxLayout.PAGE_AXIS));
activityPanel.setVisible(false);
activityPanel.add(new JSeparator());
mainWindow.getContentPane().add(activityPanel, BorderLayout.PAGE_END);
// center the window on the primary monitor
mainWindow.getContentPane().add(mainContainer, BorderLayout.CENTER);
mainWindow.setLocationRelativeTo(null);
mainWindow.setVisible(true);
// here we can check for Session information
SavedSession session = Config.getSavedSession();
if (session != null) {
// Wait for proxy server init
App.waitForInit();
try {
WhoamiInfo whoami = ThriftManager.getNewSatelliteClient(
GraphicalCertHandler.getSslContext(session.address), session.address,
App.THRIFT_SSL_PORT, App.THRIFT_TIMEOUT_MS).whoami(session.token);
Session.initialize(whoami, session.address, session.token, session.masterToken);
ThriftManager.setSatelliteAddress(
GraphicalCertHandler.getSslContext(Session.getSatelliteAddress()),
Session.getSatelliteAddress(), App.THRIFT_SSL_PORT, App.THRIFT_TIMEOUT_MS);
LOGGER.info("Saved session used for resume.");
} catch (Exception e1) {
LOGGER.info("Session resume failed.", e1);
}
}
// Session resume probably failed, show login window
if (Session.getSatelliteToken() == null) {
// User did not login, show the login mask
LoginWindow.open(mainWindow);
}
mainWindow.setTitle("bwLehrstuhl - " + Session.getFirstName() + " " + Session.getLastName() + " ["
+ Session.getSatelliteAddress() + "]");
// Show main menu by default
showPage(MainMenuWindow.class);
}
/**
* Request application quit. Will show a message box asking the user for
* confirmation.
*/
protected static void askApplicationQuit() {
boolean open = false;
for (ActivityPanel activity : activities) {
if (activity.wantConfirmQuit()) {
open = true;
break;
}
}
if (!open) {
Window[] windows = Window.getWindows();
for (Window window : windows) {
if (window.isVisible() && window instanceof UiFeedback
&& ((UiFeedback) window).wantConfirmQuit()) {
open = true;
break;
}
}
}
if (!open
|| Gui.showMessageBox(mainWindow, "Are you sure you want to quit?",
MessageType.QUESTION_YESNO, null, null)) {
Gui.exit(0);
}
isQuitQuestionOpen = false;
}
/**
* Register a page that can be displayed in the main window.
*
* @param window
*/
private static synchronized void registerPage(CompositePage window) {
Class<? extends CompositePage> clazz = window.getClass();
if (pages.containsKey(clazz))
throw new IllegalArgumentException("Page " + clazz.getSimpleName() + " already registered!");
pages.put(clazz, window);
mainContainer.add(window);
window.setVisible(false);
}
private static void addPanel(ActivityPanel panel) {
activities.add(panel);
activityPanel.add(panel);
activityPanel.setVisible(true);
mainWindow.validate();
}
public static void addUpload(UploadWizardState state) {
addPanel(new UploadPanel(state));
}
public static void addDownload(String imageName, String diskFile, DownloadTask dlTask) {
addPanel(new DownloadPanel(imageName, diskFile, dlTask));
}
public static void removeActivity(ActivityPanel panel) {
activities.remove(panel);
activityPanel.remove(panel);
if (activities.isEmpty())
activityPanel.setVisible(false);
mainWindow.validate();
}
private static void createMenu() {
// the File menu button
JMenuBar menuBar = new JMenuBar();
mainWindow.setJMenuBar(menuBar);
JMenu cascadeFileMenu = new JMenu("Session");
menuBar.add(cascadeFileMenu);
JMenuItem logoutItem = new JMenuItem("Logout");
cascadeFileMenu.add(logoutItem);
JMenuItem exitItem = new JMenuItem("Exit");
cascadeFileMenu.add(exitItem);
// the About menu button
JMenu cascadeAboutMenu = new JMenu("About");
menuBar.add(cascadeAboutMenu);
JMenuItem disclaimerItem = new JMenuItem("Disclaimer");
JMenuItem virtualizerNoticeItem = new JMenuItem("Virtualizer");
cascadeAboutMenu.add(disclaimerItem);
cascadeAboutMenu.add(virtualizerNoticeItem);
menuBar.add(Box.createHorizontalGlue());
final JLabel memStats = new JLabel();
menuBar.add(memStats);
// Define actions
logoutItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Config.saveCurrentSession("", "", "");
askApplicationQuit();
}
});
exitItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
askApplicationQuit();
}
});
disclaimerItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DisclaimerWindow.open(mainWindow);
}
});
virtualizerNoticeItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
VirtualizerNoticeWindow.open(mainWindow);
}
});
// Debug label
QuickTimer.scheduleAtFixedDelay(new Task() {
@Override
public void fire() {
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
long totalMemory = rt.totalMemory();
long usedMemory = totalMemory - rt.freeMemory();
String txt = "[" + FormatHelper.bytes(usedMemory, false) + "/"
+ FormatHelper.bytes(totalMemory, false);
if (maxMemory != Long.MAX_VALUE) {
txt += ", limit: " + FormatHelper.bytes(maxMemory, false);
}
txt += "]";
if (Session.getUserId() != null) {
try {
SatelliteStatus status = ThriftManager.getSatClient().getStatus();
txt += " [" + FormatHelper.bytes(status.availableStorageBytes, false) + "]";
} catch (TException e) {
//
}
}
final String labelText = txt;
Gui.asyncExec(new Runnable() {
@Override
public void run() {
memStats.setText(labelText);
}
});
}
}, 10, 2001);
}
}