Package org.rssowl.ui.internal

Source Code of org.rssowl.ui.internal.ApplicationWorkbenchWindowAdvisor

/*   **********************************************************************  **
**   Copyright notice                                                       **
**                                                                          **
**   (c) 2005-2006 RSSOwl Development Team                                  **
**   http://www.rssowl.org/                                                 **
**                                                                          **
**   All rights reserved                                                    **
**                                                                          **
**   This program and the accompanying materials are made available under   **
**   the terms of the Eclipse Public License v1.0 which accompanies this    **
**   distribution, and is available at:                                     **
**   http://www.rssowl.org/legal/epl-v10.html                               **
**                                                                          **
**   A copy is found in the file epl-v10.html and important notices to the  **
**   license from the team is found in the textfile LICENSE.txt distributed **
**   in this package.                                                       **
**                                                                          **
**   This copyright notice MUST APPEAR in all copies of the file!           **
**                                                                          **
**   Contributors:                                                          **
**     RSSOwl Development Team - initial API and implementation             **
**                                                                          **
**  **********************************************************************  */

package org.rssowl.ui.internal;

import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tray;
import org.eclipse.swt.widgets.TrayItem;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
import org.rssowl.core.Owl;
import org.rssowl.core.internal.persist.pref.DefaultPreferences;
import org.rssowl.core.persist.INews;
import org.rssowl.core.persist.dao.DynamicDAO;
import org.rssowl.core.persist.dao.IPreferenceDAO;
import org.rssowl.core.persist.event.NewsAdapter;
import org.rssowl.core.persist.event.NewsEvent;
import org.rssowl.core.persist.event.PreferenceEvent;
import org.rssowl.core.persist.event.PreferenceListener;
import org.rssowl.core.persist.event.runnable.EventType;
import org.rssowl.core.persist.pref.IPreferenceScope;
import org.rssowl.core.util.LoggingSafeRunnable;
import org.rssowl.ui.internal.editors.feed.FeedView;
import org.rssowl.ui.internal.util.JobRunner;

import java.util.Set;

/**
* @author bpasero
*/
public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {

  /* WebSite class being used for the Browser on Windows only */
  private static final String SWT_BROWSER_WIN = "org.eclipse.swt.browser.WebSite";

  /** Key for Data-Slot in Controls that support this Hook */
  public static final String FOCUSLESS_SCROLL_HOOK = "org.rssowl.ui.internal.FocuslessScrollHook";

  private TrayItem fTrayItem;
  private boolean fTrayTeasing;
  private boolean fTrayEnabled;
  private boolean fMinimizedToTray;
  private ApplicationActionBarAdvisor fActionBarAdvisor;
  private LocalResourceManager fResources;
  private IPreferenceScope fPreferences;
  private boolean fBlockIconifyEvent;
  private boolean fMinimizeFromClose;

  /* Listeners */
  private NewsAdapter fNewsListener;
  private ShellListener fTrayShellListener;
  private PreferenceListener fPrefListener;

  /**
   * @param configurer
   */
  public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
    super(configurer);
    fResources = new LocalResourceManager(JFaceResources.getResources());
  }

  /*
   * @see org.eclipse.ui.application.WorkbenchWindowAdvisor#createActionBarAdvisor(org.eclipse.ui.application.IActionBarConfigurer)
   */
  @Override
  public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) {
    fActionBarAdvisor = new ApplicationActionBarAdvisor(configurer);
    return fActionBarAdvisor;
  }

  /*
   * @see org.eclipse.ui.application.WorkbenchWindowAdvisor#preWindowOpen()
   */
  @Override
  public void preWindowOpen() {
    IWorkbenchWindowConfigurer configurer = getWindowConfigurer();

    /* Set Window State and define visibility of UI elements */
    configurer.setShowCoolBar(true);
    configurer.setShowPerspectiveBar(false);
    configurer.setShowStatusLine(true);
    configurer.setShowMenuBar(true);
    configurer.setShowFastViewBars(true);
    configurer.setShowProgressIndicator(true);
    configurer.setTitle("RSSOwl"); //$NON-NLS-1$

    /* Apply DND Support for Editor Area */
    configurer.addEditorAreaTransfer(LocalSelectionTransfer.getTransfer());
    configurer.configureEditorAreaDropListener(new EditorDNDImpl());
  }

  /**
   * @see org.eclipse.ui.application.WorkbenchWindowAdvisor#postWindowOpen()
   */
  @Override
  public void postWindowOpen() {
    SafeRunner.run(new LoggingSafeRunnable() {
      public void run() throws Exception {

        /* Retrieve Preferences */
        fPreferences = Owl.getPreferenceService().getGlobalScope();

        /* Hook TrayItem if supported on OS and 1st Window */
        if (fPreferences.getBoolean(DefaultPreferences.TRAY_ON_MINIMIZE) || fPreferences.getBoolean(DefaultPreferences.TRAY_ON_CLOSE))
          enableTray();

        /* Win only: Allow Scroll over Cursor-Control */
        if (Application.IS_WINDOWS)
          hookFocuslessScrolling(getWindowConfigurer().getWindow().getShell().getDisplay());

        /* Register Listeners */
        registerListeners();
      }
    });
  }

  /*
   * @see org.eclipse.ui.application.WorkbenchWindowAdvisor#preWindowShellClose()
   */
  @Override
  public boolean preWindowShellClose() {
    final boolean[] res = new boolean[] { true };
    SafeRunner.run(new LoggingSafeRunnable() {
      public void run() throws Exception {

        /* Check if Prefs tell to move to tray */
        if (fPreferences.getBoolean(DefaultPreferences.TRAY_ON_CLOSE)) {
          fMinimizeFromClose = true;
          getWindowConfigurer().getWindow().getShell().notifyListeners(SWT.Iconify, new Event());
          res[0] = false;
          fMinimizeFromClose = false;
        }
      }
    });

    return res[0];
  }

  boolean isMinimizedToTray() {
    return fMinimizedToTray;
  }

  boolean isMinimized() {
    return getWindowConfigurer().getWindow().getShell().getMinimized();
  }

  private void registerListeners() {

    /* Add Shell sListener */
    getWindowConfigurer().getWindow().getShell().addShellListener(new ShellAdapter() {
      @Override
      public void shellIconified(ShellEvent e) {
        if (!fBlockIconifyEvent)
          onMinimize();
      }
    });

    /* Listen on Preferences Changes */
    fPrefListener = new PreferenceListener() {
      public void entitiesAdded(Set<PreferenceEvent> events) {
        onPreferencesChange(events, EventType.PERSIST);
      }

      public void entitiesDeleted(Set<PreferenceEvent> events) {
        onPreferencesChange(events, EventType.REMOVE);
      }

      public void entitiesUpdated(Set<PreferenceEvent> events) {
        onPreferencesChange(events, EventType.UPDATE);
      }
    };
    DynamicDAO.getDAO(IPreferenceDAO.class).addEntityListener(fPrefListener);
  }

  private void unregisterListeners() {
    DynamicDAO.getDAO(IPreferenceDAO.class).removeEntityListener(fPrefListener);
  }

  private void onPreferencesChange(Set<PreferenceEvent> events, EventType type) {
    IPreferenceScope defaultScope = Owl.getPreferenceService().getDefaultScope();
    boolean useTray = false;
    boolean affectsTray = false;

    for (PreferenceEvent event : events) {
      String key = event.getEntity().getKey();

      /* Tray Preference Change: Tray on Minimize */
      if (DefaultPreferences.TRAY_ON_MINIMIZE.equals(key)) {
        affectsTray = true;
        if (type == EventType.REMOVE)
          useTray = defaultScope.getBoolean(DefaultPreferences.TRAY_ON_MINIMIZE) || fPreferences.getBoolean(DefaultPreferences.TRAY_ON_CLOSE);
        else
          useTray = event.getEntity().getBoolean() || fPreferences.getBoolean(DefaultPreferences.TRAY_ON_CLOSE);
      }

      /* Tray Preference Change: Tray on Close */
      else if (DefaultPreferences.TRAY_ON_CLOSE.equals(key)) {
        affectsTray = true;
        if (type == EventType.REMOVE)
          useTray = defaultScope.getBoolean(DefaultPreferences.TRAY_ON_CLOSE) || fPreferences.getBoolean(DefaultPreferences.TRAY_ON_MINIMIZE);
        else
          useTray = event.getEntity().getBoolean() || fPreferences.getBoolean(DefaultPreferences.TRAY_ON_MINIMIZE);
      }

      /* Enable Tray */
      if (affectsTray && useTray && !fTrayEnabled) {
        PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
          public void run() {
            enableTray();
          }
        });
      }

      /* Disable Tray */
      else if (affectsTray && !useTray && fTrayEnabled) {
        PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
          public void run() {
            disableTray();
          }
        });
      }
    }
  }

  /*
   * @see org.eclipse.ui.application.WorkbenchWindowAdvisor#dispose()
   */
  @Override
  public void dispose() {
    unregisterListeners();

    if (fTrayItem != null)
      fTrayItem.dispose();

    if (fNewsListener != null)
      DynamicDAO.removeEntityListener(INews.class, fNewsListener);

    fResources.dispose();
  }

  private void onMinimize() {

    /* Mark displayed News as Read on Minimize if set in Preferences */
    IEditorPart activeEditor = OwlUI.getActiveEditor();
    if (activeEditor != null && activeEditor instanceof FeedView) {
      FeedView feedView = (FeedView) activeEditor;
      feedView.notifyUIEvent(FeedView.UIEvent.MINIMIZE);
    }
  }

  /* Enable System-Tray Support */
  private void enableTray() {

    /* Avoid that this is being called redundantly */
    if (fTrayEnabled)
      return;

    /* Only enable for Primary Window */
    IWorkbenchWindow primaryWindow = OwlUI.getPrimaryWindow();
    if (primaryWindow == null || !primaryWindow.equals(getWindowConfigurer().getWindow()))
      return;

    final Shell shell = primaryWindow.getShell();
    final Tray tray = shell.getDisplay().getSystemTray();

    /* Tray not support on the OS */
    if (tray == null)
      return;

    /* Create Item in Tray */
    fTrayItem = new TrayItem(tray, SWT.NONE);
    fTrayItem.setToolTipText("RSSOwl");
    fTrayEnabled = true;

    if (Application.IS_WINDOWS)
      fTrayItem.setVisible(false);

    /* Apply Image */
    fTrayItem.setImage(OwlUI.getImage(fResources, OwlUI.TRAY_OWL));

    /* Minimize to Tray on Shell Iconify if set */
    fTrayShellListener = new ShellAdapter() {

      @Override
      public void shellIconified(ShellEvent e) {
        if (!fBlockIconifyEvent && (fMinimizeFromClose || fPreferences.getBoolean(DefaultPreferences.TRAY_ON_MINIMIZE)))
          moveToTray(shell);
      }
    };
    shell.addShellListener(fTrayShellListener);

    /* Show Menu on Selection */
    fTrayItem.addListener(SWT.MenuDetect, new Listener() {
      public void handleEvent(Event event) {
        MenuManager trayMenu = new MenuManager();

        /* Restore */
        trayMenu.add(new ContributionItem() {
          @Override
          public void fill(Menu menu, int index) {
            MenuItem restoreItem = new MenuItem(menu, SWT.PUSH);
            restoreItem.setText("Restore");
            restoreItem.addSelectionListener(new SelectionAdapter() {
              @Override
              public void widgetSelected(SelectionEvent e) {
                restoreFromTray(shell);
              }
            });
            menu.setDefaultItem(restoreItem);
          }
        });

        /* Separator */
        trayMenu.add(new Separator());

        /* Other Items */
        fActionBarAdvisor.fillTrayItem(trayMenu);

        Menu menu = trayMenu.createContextMenu(shell);
        menu.setVisible(true);
      }
    });

    /* Handle DefaultSelection */
    fTrayItem.addListener(SWT.DefaultSelection, new Listener() {
      public void handleEvent(Event event) {

        /* Restore from Tray */
        if (!shell.isVisible())
          restoreFromTray(shell);

        /* Move to Tray */
        else if (!Application.IS_WINDOWS)
          moveToTray(shell);
      }
    });

    /* Indicate new News in Tray */
    fNewsListener = new NewsAdapter() {

      @Override
      public void entitiesAdded(Set<NewsEvent> events) {
        JobRunner.runInUIThread(fTrayItem, new Runnable() {
          public void run() {

            /* Update Icon only when Tray is visible and not yet teasing */
            if (!fTrayItem.getVisible() || fTrayTeasing || shell.getVisible())
              return;

            fTrayTeasing = true;
            fTrayItem.setImage(OwlUI.getImage(fResources, OwlUI.TRAY_OWL_TEASING));
          }
        });
      }
    };
    DynamicDAO.addEntityListener(INews.class, fNewsListener);
  }

  /* Move to System Tray */
  private void moveToTray(Shell shell) {
    if (Application.IS_WINDOWS)
      fTrayItem.setVisible(true);

    /*
     * Bug in SWT: For some reason, calling setVisible(false) here will result
     * in a second Iconify Event. The fix is to disable processing of this event
     * meanwhile.
     */
    fBlockIconifyEvent = true;
    try {
      shell.setVisible(false);
    } finally {
      fBlockIconifyEvent = false;
    }

    fMinimizedToTray = true;

    /*
     * Bug in Eclipse (#180881): For some reason the workbench-layout is broken,
     * when restoring from the Tray after it has been moved to tray with
     * Shell-Close. Force a layout() to avoid this issue.
     */
    shell.setLayoutDeferred(true);
  }

  /* Restore from System Tray */
  void restoreFromTray(Shell shell) {
    shell.setVisible(true);
    shell.setLayoutDeferred(false);
    shell.setActive();

    /* Un-Minimize if minimized */
    if (shell.getMinimized())
      shell.setMinimized(false);

    if (Application.IS_WINDOWS)
      fTrayItem.setVisible(false);

    if (fTrayTeasing)
      fTrayItem.setImage(OwlUI.getImage(fResources, OwlUI.TRAY_OWL));

    fTrayTeasing = false;
    fMinimizedToTray = false;
  }

  /* Disable System-Tray Support */
  private void disableTray() {

    /* Avoid that this is being called redundantly */
    if (!fTrayEnabled)
      return;

    /* First make sure to have the Window restored */
    restoreFromTray(getWindowConfigurer().getWindow().getShell());

    fTrayEnabled = false;
    fMinimizedToTray = false;

    if (fTrayItem != null)
      fTrayItem.dispose();

    if (fNewsListener != null)
      DynamicDAO.removeEntityListener(INews.class, fNewsListener);

    if (fTrayShellListener != null)
      getWindowConfigurer().getWindow().getShell().removeShellListener(fTrayShellListener);
  }

  /* Support for focusless scrolling */
  private void hookFocuslessScrolling(final Display display) {
    display.addFilter(SWT.MouseWheel, new Listener() {
      public void handleEvent(Event event) {
        Control control = display.getCursorControl();

        /* Control must be non-focus undisposed */
        if (control == null || control.isDisposed() || control.isFocusControl())
          return;

        /* Pass focus to control and disable event if allowed */
        boolean isBrowser = SWT_BROWSER_WIN.equals(control.getClass().getName());
        if (isBrowser || control.getData(FOCUSLESS_SCROLL_HOOK) != null) {

          /* Break Condition */
          control.setFocus();

          /* Re-Post Event to Cursor Control */
          event.doit = false;
          event.widget = control;
          display.post(event);
        }
      }
    });
  }
}
TOP

Related Classes of org.rssowl.ui.internal.ApplicationWorkbenchWindowAdvisor

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.