Package org.fenrir.yggdrasil.ui

Source Code of org.fenrir.yggdrasil.ui.ApplicationWindowManager

package org.fenrir.yggdrasil.ui;

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;

import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.JPanel;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;

import javax.inject.Inject;

import org.jdesktop.jxlayer.JXLayer;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.fenrir.yggdrasil.core.AbstractApplication;
import org.fenrir.yggdrasil.core.ApplicationContext;
import org.fenrir.yggdrasil.core.definition.ProductDefinition;
import org.fenrir.yggdrasil.core.event.IWorkspaceEventListener;
import org.fenrir.yggdrasil.core.event.annotation.EventListener;
import org.fenrir.yggdrasil.core.service.IPreferenceService;
import org.fenrir.yggdrasil.core.service.IWorkspaceAdministrationService;
import org.fenrir.yggdrasil.core.util.ICallback;
import org.fenrir.yggdrasil.ui.dialog.ErrorDialog;
import org.fenrir.yggdrasil.ui.dialog.ErrorFrameDialog;
import org.fenrir.yggdrasil.ui.event.ApplicationWindowListener;
import org.fenrir.yggdrasil.ui.mvc.AbstractPerspective;
import org.fenrir.yggdrasil.ui.mvc.AbstractView;
import org.fenrir.yggdrasil.ui.mvc.EmptyPerspective;
import org.fenrir.yggdrasil.ui.widget.InProcessLayerUI;

/**
* TODO v1.0 Documentació
* TODO v1.0 Internacionalitzar
* @author Antonio Archilla Nava
* @version v0.1.20140723
*/
@EventListener(definitions=IWorkspaceEventListener.class)
public class ApplicationWindowManager implements IWorkspaceEventListener
{
    private static Logger log = LoggerFactory.getLogger(ApplicationWindowManager.class);

    private static ApplicationWindowManager instance;

    private JFrame mainWindow;
    private TrayIcon trayIcon;
    // S'inicialitzarà en crear les vistes de l'aplicació
    private ApplicationTray applicationTray;
    private JXLayer layer;
    private InProcessLayerUI layerUI;
   
    // Necessari per poder canviar entre les prespectives de l'àrea principal
    private JPanel mainArea;
    private CardLayout mainAreaLayout;
    private HashMap<String, AbstractView<?>> viewRegistry = new HashMap<String, AbstractView<?>>();
    private HashMap<String, AbstractPerspective> perspectiveRegistry = new HashMap<String, AbstractPerspective>();
    private String currentPerspectiveId;

    @Inject
    private IPreferenceService preferenceService;

    @Inject
    private IWorkspaceAdministrationService workspaceAdministrationService;

    private ApplicationWindowListener windowListener;

    private ApplicationWindowManager()
    {
      windowListener = new ApplicationWindowListener();
      ApplicationContext applicationContext = ApplicationContext.getInstance();
        applicationContext.injectMembers(windowListener);
    }
 
    public static ApplicationWindowManager getInstance()
    {
        if(instance==null){
            instance = new ApplicationWindowManager();
            ApplicationContext applicationContext = ApplicationContext.getInstance();
            applicationContext.injectMembers(instance);           
        }

        return instance;
    }

    public void setPreferenceService(IPreferenceService preferenceService)
    {
        this.preferenceService = preferenceService;
    }

    public void setWorkspaceAdministrationService(IWorkspaceAdministrationService workspaceAdministrationService)
    {
        this.workspaceAdministrationService = workspaceAdministrationService;
    }

    public void initialize(AbstractApplication application)
    {
      windowListener.setApplicationInstance(application);
    }
   
    public void notifyPreWindowOpenEvent()
    {
      windowListener.preWindowOpen();
    }
 
    public void createWindow() throws InvocationTargetException, InterruptedException
    {
        // TODO Si la finestra principal ja ha estat creada llançar excepció
        mainWindow = new JFrame();
        JFrame.setDefaultLookAndFeelDecorated(true);   
        SwingUtilities.invokeAndWait(new Runnable()
        {
            @Override
            public void run()
            {
                // #29: Error en el càlcul de la posició del cursor del mouse quan la finestra està maximitzada
                if(Arrays.asList("gnome-shell", "mate", "other...").contains(System.getenv("DESKTOP_SESSION"))){
                    try{
                        Class<?> xwm = Class.forName("sun.awt.X11.XWM");
                        Field awt_wmgr = xwm.getDeclaredField("awt_wmgr");
                        awt_wmgr.setAccessible(true);
                        Field other_wm = xwm.getDeclaredField("OTHER_WM");
                        other_wm.setAccessible(true);
                        if(awt_wmgr.get(null).equals(other_wm.get(null))){
                            Field metacity_wm = xwm.getDeclaredField("METACITY_WM");
                            metacity_wm.setAccessible(true);
                            awt_wmgr.set(null, metacity_wm.get(null));
                        }
                    }
                    catch(Exception e){
                        /* Encara que sigui no es pugui calcular correctament
                         * la posició del mouse es continua l'execució
                         */
                        log.error("Error: " + e.getMessage(), e);
                    }
                }
               
                // S'especifica el look and feel. Si no es troba per defecte serà Metal
                String laf = preferenceService.getProperty(UIConstants.PREFERENCES_UI_LOOK_AND_FEEL_SKIN);
                if(StringUtils.isNotBlank(laf)){
                    try{               
                        UIManager.setLookAndFeel(laf);
                        // Es important fer la crida a l'update per actualitzar els painters i no doni error per intentar fer servir els per defecte
                        SwingUtilities.updateComponentTreeUI(mainWindow);
                    }
                    catch(Exception e){
                        log.error("Error al carregar look and feel {}: {}", new Object[]{laf, e.getMessage(), e});
                    }
                }
                                             
                // S'especifica el títol.
                ProductDefinition productDefinition = ApplicationContext.getInstance().getPluginRegistry().getProductDefinition();
                String fullVersionName = productDefinition.getFullVersionName();
                mainWindow.setTitle(fullVersionName);
                // Creació del menú de l'aplicació               
                JMenuBar menuBar = (JMenuBar)ApplicationContext.getInstance().getRegisteredComponent(JMenuBar.class);
                mainWindow.setJMenuBar(menuBar);
                // Creació de la UI principal
                createInitialUI();
                switchToPerspective(EmptyPerspective.ID);
               
                mainWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                // Mida de la finestra per defecte per quan està desmaximitzada
                mainWindow.setPreferredSize(new Dimension(800, 600));
                mainWindow.setMinimumSize(new Dimension(640, 480));
                mainWindow.pack();               
               
                // Icona a la safata del sistema
                if(SystemTray.isSupported()){
                    SystemTray tray = SystemTray.getSystemTray();
                   
                    String icon = productDefinition.getIcon();
                    Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource(icon));
                    trayIcon = new TrayIcon(image, fullVersionName);
                    // Es redimensiona la imatge per tal que s'adapti a l'espai disponible
                    trayIcon.setImageAutoSize(true);
                    try{
                        tray.add(trayIcon);
                    }
                    catch(AWTException e){
                        log.error("Error en afegir la icona de l'aplicació a la safata del sistema");
                    }
                }
                else{
                    log.warn("Safata del sistema no disponible");
                }
            }
        });
       
        mainWindow.addWindowListener(windowListener);
    }
 
    @Override
    public void beforeWorkspaceLoad()
    {
       
    }
   
    @Override
    public void workspaceLoaded()
    {
       
    }

    @Override
    public void beforeWorkspaceUnload()
    {
       
    }
   
    @Override
    public void workspaceUnloaded()
    {
        mainWindow.getContentPane().removeAll();
    }
 
    public JFrame getMainWindow()
    {
        return mainWindow;
    }

    public void showWindow()
    {
        SwingUtilities.invokeLater(new Runnable()
        {           
            @Override
            public void run()
            {
                // Es centra al mig de la pantalla
                Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
                mainWindow.setLocation((d.width - mainWindow.getWidth()) / 2, (d.height - mainWindow.getHeight()) / 2);
                mainWindow.setVisible(true);
                // Es maximitza la finestra
                mainWindow.setExtendedState(mainWindow.getExtendedState() | JFrame.MAXIMIZED_BOTH);
            }
        });
    }
 
    public void closeWindow()
    {
        SwingUtilities.invokeLater(new Runnable()
        {           
            @Override
            public void run()
            {
                mainWindow.setVisible(false);
                mainWindow.dispose();
            }
        });
    }

    public boolean isMainWindowActive()
    {
        return mainWindow.isActive();
    }
   
    public void displaySystemTrayMessage(String caption, String message, TrayIcon.MessageType messageType)
    {       
        trayIcon.displayMessage(caption, message, messageType);
    }
   
    public void displayErrorMessage(final String message, final Throwable error)
    {
        if(mainWindow!=null){
            if(SwingUtilities.isEventDispatchThread()){           
                new ErrorDialog(mainWindow, message, error).open();
            }
            else{
                try{
                    SwingUtilities.invokeAndWait(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            new ErrorDialog(mainWindow, message, error).open();
                        }
                    });
                }
                catch(Exception e){
                    log.error("Error mostrant finestra d'error: {}", e.getMessage(), e);
                }
            }
        }
        else{
            try{
                displayStandaloneErrorMessage(message, error);
            }
            catch(Exception e){
                log.error("Error obrint finestra d'error: {}", e.getMessage(), e);
            }
        }                               
    }
   
    /**
     * ATENCIÓ!! Aquest mètode només s'haurà d'utilitzar en cas de no poder inicial el contexte bàsic de l'aplicació,
     * i per tant, falli la creació del manager.
     * @param message
     * @param error
     */
    public static void displayStandaloneErrorMessage(final String message, final Throwable error)
    {       
        try{
          ErrorFrameDialog dialog = new ErrorFrameDialog(message, error);
          dialog.setCloseCallback(new ICallback<Void, Void>()
      {
        @Override
        public Void execute(Void cArg)
        {
          System.exit(-1);
          return null;
        }
      });
         
            dialog.open();
        }
        catch(Exception e){
            log.error("Error mostrant finestra d'error: {}", e.getMessage(), e);
        }               
    }
   
    public void setInProcessMessage(String inProcessMessage)
    {
        layerUI.setMessage(inProcessMessage);
    }
   
    public void showInProcess(final boolean inProcess)
    {
        if(SwingUtilities.isEventDispatchThread()){           
            layerUI.setLocked(inProcess);
            layer.repaint();
        }
        else{
            try{
                SwingUtilities.invokeAndWait(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        layerUI.setLocked(inProcess);
                        layer.repaint();
                    }
                });
            }
            catch(Exception e){
                log.error("Error mostrant la capa wait: {}", e.getMessage(), e);
            }
        }
    }
   
    public void createInitialUI()
    {
        JPanel panel = new JPanel();
        // 5 px de marge per tal que no quedi enganxada l'area de notificació
        panel.setLayout(new BorderLayout(0, 5));
        // Es crea el panell a on aniran les perspectives
        mainArea = new JPanel();
        mainAreaLayout = new CardLayout();
        mainArea.setLayout(mainAreaLayout);
        panel.add(mainArea, BorderLayout.CENTER);
        // Es crea la zona d'avisos de l'aplicació
        applicationTray = (ApplicationTray)ApplicationContext.getInstance().getRegisteredComponent(ApplicationTray.class);      
        panel.add(applicationTray, BorderLayout.SOUTH);
        // Es crea la capa per sobre la la UI de l'aplicació que permetrà bloquejar la interacció de l'usuari quan calgui
        layer = new JXLayer(panel);         
        layerUI = new InProcessLayerUI();        
        layer.setUI(layerUI);
        // S'afageixen les vistes creades a la finestra
        mainWindow.getContentPane().setLayout(new BorderLayout());
        mainWindow.getContentPane().add(layer, BorderLayout.CENTER);       
        /* Necessari per refrescar el panell i que es mostrin els components afegits
         * en cas que es crein les vistes després que s'hagi creat la finestra principal,
         * per exemple, durant la primera execució quan no hi ha workspace per defecte.
         */
        mainWindow.getContentPane().validate();  
    }
   
    public void switchToDefaultPerspective()
    {
        String defaultId = preferenceService.getProperty(UIConstants.PREFERENCES_UI_DEFAULT_PERSPECTIVE);
        switchToPerspective(defaultId);
    }
   
    public void switchToPerspective(String id)
    {
      // Si la perspectiva actual és a la que es vol canviar, no es fa res
      if(id.equals(currentPerspectiveId)){
        return;
      }
     
        if(!perspectiveRegistry.containsKey(id)){
          AbstractPerspective perspective = (AbstractPerspective)ApplicationContext.getInstance().getRegisteredComponent(AbstractPerspective.class, id);
            mainArea.add(perspective, id);
            // Es necessari repintar el panell tal i com indica el mètode add
            mainArea.validate();
            perspectiveRegistry.put(id, perspective);
        }
        mainAreaLayout.show(mainArea, id);
        currentPerspectiveId = id;
    }
   
    public AbstractPerspective getCurrentPerspective()
    {
      return getPerspective(currentPerspectiveId);
    }
   
    public AbstractPerspective getPerspective(String id)
    {
      if(id!=null){
        return perspectiveRegistry.get(id);
      }
     
      return null;
    }
   
    public AbstractView<?> getViewFromRegistry(String id)
    {
      return viewRegistry.get(id);
    }
   
    public <T extends AbstractView<?>> void addViewToRegistry(String id, Class<T> viewClass)
    {
      T view = (T)ApplicationContext.getInstance().getRegisteredComponent(viewClass);
      addViewToRegistry(id, view);
    }
   
    public <T extends AbstractView<?>> void addViewToRegistry(String id, AbstractView<?> view)
    {
      viewRegistry.put(id, view);
    }
   
    public void removeViewFromRegistry(String id)
    {
      AbstractView<?> view = viewRegistry.remove(id);
      for(AbstractPerspective perspective:perspectiveRegistry.values()){
        perspective.viewRemoved(view);
      }
    }
}
TOP

Related Classes of org.fenrir.yggdrasil.ui.ApplicationWindowManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.