/* * XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq * Copyright (C) 2013 Marko Zivkovic * Contact Information: marko88zivkovic at gmail dot 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; either version 2 of the License, or (at your option) * any later version. 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. * This Java source code belongs to XLogo4Schools, written by Marko Zivkovic * during his Bachelor thesis at the computer science department of ETH Zurich, * in the year 2013 and/or during future work. * It is a reengineered version of XLogo written by Loic Le Coq, published * under the GPL License at http://xlogo.tuxfamily.org/ * Contents of this file were entirely written by Marko Zivkovic */ package xlogo.gui.welcome; import java.awt.event.*; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.JTextComponent; import java.awt.*; import java.io.IOException; import xlogo.gui.components.X4SFrame; import xlogo.interfaces.Observable.PropertyChangeListener; import xlogo.messages.MessageKeys; import xlogo.messages.async.dialog.DialogMessenger; import xlogo.storage.Storable; import xlogo.storage.WSManager; import xlogo.storage.global.GlobalConfig; import xlogo.storage.global.GlobalConfig.GlobalProperty; import xlogo.storage.workspace.WorkspaceConfig; import xlogo.utils.Utils; import xlogo.utils.WebPage; import xlogo.Application; /** * This was initially called {@code Selection_Langue} and it was only displayed when the Application was opened for the very first time. * Now this has become {@code WelcomeScreen}, as it was enhanced with more options than just language selection: *
  • User Account Selection / Creation
  • *
  • Storage Location (master password required)
  • * @author Marko */ public class WelcomeScreen extends X4SFrame { JFrame frame; private JLabel label; private JLabel workspace; private JLabel username; private JComboBox workspaceSelection; private JComboBox userSelection; private JButton openWorkspaceSettingsBtn; private JButton enterButton; private JButton infoButton; private JButton gplButton; private JPanel panel; private GroupLayout groupLayout; private WorkspaceSettings workspaceSettings; private ActionListener onApplicationEnterListener; private PropertyChangeListener onWorkspaceListChangeListener; private PropertyChangeListener onEnterWorkspaceListener; /** * * @param listener to be informed when the user is ready to enter the application */ public WelcomeScreen(ActionListener onApplicationEnterListener) { this.onApplicationEnterListener = onApplicationEnterListener; } @Override public JFrame getFrame() { return frame; } @Override protected void initComponent() { frame = new JFrame(){ private static final long serialVersionUID = -6730403281163492211L; @Override public void dispose() { try { WSManager.getInstance().storeAllSettings(); } catch (IOException e) { DialogMessenger.getInstance().dispatchMessage(translate("ws.error.title"), translate("storage.could.not.store.gc")); } super.dispose(); } }; // Window frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Utils.class.getResource("Icon_x4s.png"))); frame.setTitle("XLogo4Schools"); workspace = new JLabel("Workspace"); username = new JLabel("User"); workspaceSelection = new JComboBox<>(); userSelection = new JComboBox<>(); openWorkspaceSettingsBtn = new JButton("Settings"); enterButton = new JButton("Enter"); infoButton = new JButton(); gplButton = new JButton(); panel = new JPanel(); // The XLogo4Schools logo //ImageIcon logo = Utils.dimensionne_image("Logo_xlogo4schools.png", this); infoButton.setIcon(createImageIcon("info_icon.png", "Info", 40, 40)); gplButton.setIcon(createImageIcon("gnu_gpl.png", "GPL", 40, 40)); label = new JLabel(createImageIcon("Logo_xlogo4schools.png", "XLogo4Schools", 250, 40)); populateWorkspaceList(); populateUserList(); } @Override protected void layoutComponent() { frame.getContentPane().add(panel); frame.setResizable(false); infoButton.setBorder(null); gplButton.setBorder(null); infoButton.setOpaque(false); gplButton.setOpaque(false); panel.add(workspace); panel.add(username); panel.add(workspaceSelection); panel.add(userSelection); panel.add(openWorkspaceSettingsBtn); panel.add(enterButton); panel.add(infoButton); panel.add(gplButton); workspaceSelection.setMinimumSize(new Dimension(200, 25)); userSelection.setMinimumSize(new Dimension(200, 25)); workspaceSelection.setMaximumSize(new Dimension(200, 25)); userSelection.setMaximumSize(new Dimension(200, 25)); groupLayout = new GroupLayout(panel); panel.setLayout(groupLayout); groupLayout.setAutoCreateGaps(true); groupLayout.setAutoCreateContainerGaps(true); groupLayout.setVerticalGroup(groupLayout .createSequentialGroup() .addGroup( groupLayout.createParallelGroup().addComponent(gplButton).addComponent(infoButton) .addComponent(label)) .addGroup( groupLayout.createParallelGroup().addComponent(workspace).addComponent(workspaceSelection) .addComponent(openWorkspaceSettingsBtn)) .addGroup( groupLayout.createParallelGroup().addComponent(username).addComponent(userSelection) .addComponent(enterButton))); groupLayout.setHorizontalGroup(groupLayout .createParallelGroup() .addGroup( groupLayout.createSequentialGroup().addComponent(label).addComponent(gplButton) .addComponent(infoButton)) .addGroup( groupLayout .createSequentialGroup() .addGroup( groupLayout.createParallelGroup().addComponent(workspace) .addComponent(username)) .addGroup( groupLayout.createParallelGroup().addComponent(workspaceSelection) .addComponent(userSelection)) .addGroup( groupLayout.createParallelGroup().addComponent(openWorkspaceSettingsBtn) .addComponent(enterButton)))); } private boolean ignoreGuiEvents = false; @Override protected void initEventListeners() { GlobalConfig gc = WSManager.getGlobalConfig(); onWorkspaceListChangeListener = () -> { ignoreGuiEvents = true; populateWorkspaceList(); populateUserList(); ignoreGuiEvents = false; }; onEnterWorkspaceListener = () -> { ignoreGuiEvents = true; populateWorkspaceList(); populateUserList(); ignoreGuiEvents = false; }; gc.addPropertyChangeListener(GlobalProperty.CURRENT_WORKSPACE, onEnterWorkspaceListener); gc.addPropertyChangeListener(GlobalProperty.WORKSPACES, onWorkspaceListChangeListener); workspaceSelection.addItemListener(new ItemListener(){ public void itemStateChanged(ItemEvent e) { if (ignoreGuiEvents) { return; } String workspace = (String) workspaceSelection.getSelectedItem(); enterWorkspace(workspace); } }); // Open workspace settings button openWorkspaceSettingsBtn.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { showWorkspaceSettings(); } }); // Select user combo box final JTextComponent tc = (JTextComponent) userSelection.getEditor().getEditorComponent(); tc.getDocument().addDocumentListener(new DocumentListener(){ public void removeUpdate(DocumentEvent arg0) { enableOrDisableEnter(); } public void insertUpdate(DocumentEvent arg0) { enableOrDisableEnter(); } public void changedUpdate(DocumentEvent arg0) { enableOrDisableEnter(); } private void enableOrDisableEnter() { String username = tc.getText(); enterButton.setEnabled(username != null && username.length() != 0); } }); userSelection.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { String username = (String) userSelection.getSelectedItem(); enterButton.setEnabled(username != null && username.length() != 0); } }); // Enter user space button enterButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { new Thread(new Runnable(){ @Override public void run() { enterApplication(); } }).start(); } }); gplButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { new Thread(new Runnable(){ @Override public void run() { showGPL(); } }).start(); } }); infoButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { new Thread(new Runnable(){ @Override public void run() { showInfo(); } }).start(); } }); } private void populateWorkspaceList() { GlobalConfig gc = WSManager.getGlobalConfig(); String[] workspaces = gc.getAllWorkspaces(); workspaceSelection.setModel(new DefaultComboBoxModel<>(workspaces)); selectCurrentWorkspace(); } private void selectCurrentWorkspace(){ GlobalConfig gc = WSManager.getGlobalConfig(); workspaceSelection.setSelectedItem(gc.getLastUsedWorkspace()); } private void populateUserList() { WorkspaceConfig wc = WSManager.getWorkspaceConfig(); String[] users; String lastUser = null; boolean isUserCreationAllowed = false; if (wc != null){ users = wc.getUserList(); lastUser = wc.getLastActiveUser(); isUserCreationAllowed = wc.isUserCreationAllowed(); } else { users = new String[0]; } userSelection.setModel(new DefaultComboBoxModel<>(users)); userSelection.setSelectedItem(lastUser); enterButton.setEnabled(lastUser != null && lastUser.length() > 0); userSelection.setEditable(isUserCreationAllowed); } protected void enterWorkspace(String workspaceName) { try { WSManager.getInstance().enterWorkspace(workspaceName); populateUserList(); } catch (IOException e) { DialogMessenger.getInstance().dispatchMessage(translate("ws.error.title"), translate("ws.settings.could.not.enter.wp") + "\n\n" + e.toString()); } } private synchronized void showWorkspaceSettings() { Runnable runnable = new Runnable(){ public void run() { String authentification = null; GlobalConfig gc = WSManager.getGlobalConfig(); if (gc.isPasswordRequired()) { authentification = showPasswordPopup(); if (authentification == null) return; // user cancelled the process if (!gc.authenticate(new String(authentification))) { // Could not authenticate => cancel DialogMessenger.getInstance().dispatchMessage(translate("i.am.sorry"), translate("welcome.wrong.pw")); return; } } frame.setEnabled(false); getWorkspaceSettings().showFrame(authentification); } }; new Thread(runnable).start(); } private synchronized WorkspaceSettings getWorkspaceSettings() { if (workspaceSettings == null) { workspaceSettings = new WorkspaceSettings(new ActionListener(){ public void actionPerformed(ActionEvent arg0) { // When the window is closed, repopulate workspace and user lists, update language, enable this window again. setMessageManagerParent(); setText(); populateUserList(); frame.setEnabled(true); } }); } return workspaceSettings; } protected String showPasswordPopup() { JPasswordField passwordField = new JPasswordField(); int option = JOptionPane.showConfirmDialog(frame, passwordField, translate("welcome.enter.pw"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (option == JOptionPane.OK_OPTION) { return new String(passwordField.getPassword()); } return null; } public void enterApplication() { String username = (String) userSelection.getSelectedItem(); if ((username == null) || (username.length() == 0)) return; // this should not happen since the enter button is disabled if (!Storable.checkLegalName(username)) { DialogMessenger.getInstance().dispatchError(translate(MessageKeys.NAME_ERROR_TITLE), translate(MessageKeys.ILLEGAL_NAME)); return; } // The following is in case the user entered a new name : Need to create user first WorkspaceConfig wc = WSManager.getInstance().getWorkspaceConfigInstance(); if (!wc.existsUserLogically(username)) WSManager.getInstance().createUser(username); try { WSManager.getInstance().enterUserSpace(username); } catch (IOException e) { DialogMessenger.getInstance().dispatchMessage(translate("ws.error.title"), translate("welcome.could.not.enter.user") + "\n" + e.toString()); return; } cleanupAfterEnter(); } private void cleanupAfterEnter() { if (workspaceSettings != null){ workspaceSettings.stopEventListeners(); // TODO remove each reference to workspace settings workspaceSettings = null; } WSManager.getGlobalConfig().removePropertyChangeListener(GlobalProperty.CURRENT_WORKSPACE, onEnterWorkspaceListener); WSManager.getGlobalConfig().removePropertyChangeListener(GlobalProperty.WORKSPACES, onWorkspaceListChangeListener); try { WSManager.getInstance().storeAllSettings(); } catch (IOException ignore) { } onApplicationEnterListener.actionPerformed(new ActionEvent(this, 0, null)); } @Override public void setText() { workspace.setText(translate("welcome.workspace")); username.setText(translate("welcome.username")); openWorkspaceSettingsBtn.setText(translate("welcome.settings")); enterButton.setText(translate("welcome.enter")); frame.setTitle(translate("welcome.title")); frame.pack(); } /** * Like in XLogo, almost unmodified. * It is displayed in the language of the currently selected workspace. */ private void showGPL() { JFrame frame = new JFrame(translate("menu.help.licence")); frame.setIconImage(Toolkit.getDefaultToolkit().createImage(WebPage.class.getResource("Logo_xlogo4schools.png"))); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.setSize(500, 500); WebPage editorPane = new WebPage(); editorPane.setEditable(false); String langCode = WSManager.getWorkspaceConfig().getLanguage().getLanguageCode(); String path = "gpl/gpl-" + langCode + ".html"; java.net.URL helpURL = Application.class.getResource(path); if (helpURL != null) { try { editorPane.setPage(helpURL); } catch (IOException e1) { System.err.println("Attempted to read a bad URL: " + helpURL); } } else { System.err.println("Couldn't find file: " + path); } // Put the editor pane in a scroll pane. JScrollPane editorScrollPane = new JScrollPane(editorPane); editorScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); editorScrollPane.setPreferredSize(new Dimension(250, 145)); editorScrollPane.setMinimumSize(new Dimension(10, 10)); frame.getContentPane().add(editorScrollPane); frame.setVisible(true); } private void showInfo() { JFrame frame = new JFrame(translate("welcome.info.title")); frame.setIconImage(Toolkit.getDefaultToolkit().createImage(WebPage.class.getResource("Icon_x4s.png"))); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.setSize(500, 500); WebPage editorPane = new WebPage(); editorPane.setEditable(false); String path = "gpl/x4s_info.html"; java.net.URL helpURL = Application.class.getResource(path); if (helpURL != null) { try { editorPane.setPage(helpURL); } catch (IOException e1) { System.err.println("Attempted to read a bad URL: " + helpURL); } } else { System.err.println("Couldn't find file: " + path); } // Put the editor pane in a scroll pane. JScrollPane editorScrollPane = new JScrollPane(editorPane); editorScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); editorScrollPane.setPreferredSize(new Dimension(250, 145)); editorScrollPane.setMinimumSize(new Dimension(10, 10)); frame.getContentPane().add(editorScrollPane); frame.setVisible(true); } /* * Helper */ private ImageIcon createImageIcon(String path, String description, int width, int heigth) { Image img = Toolkit.getDefaultToolkit().getImage(Utils.class.getResource(path)); return new ImageIcon(img.getScaledInstance(width, heigth, Image.SCALE_SMOOTH)); } }