/**************************************************************************** * Copyright (c) 2008, 2009 Jeremy Dowdall * 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.eclipse.org/legal/epl-v10.html * * Contributors: * Jeremy Dowdall <jeremyd@aspencloud.com> - initial API and implementation *****************************************************************************/ package org.eclipse.nebula.cwt.v; import java.util.HashMap; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; 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.Shell; import org.eclipse.swt.widgets.Widget; public class VTracker implements DisposeListener { private static VTracker tracker; static void addTopLevelPanel(VPanel panel) { VTracker tracker = instance(); if(tracker.panels == null) { tracker.panels = new HashMap<Composite, VPanel>(); } tracker.panels.put(panel.composite, panel); if(!tracker.listening) { tracker.listening = true; Display.getDefault().addFilter(SWT.FocusIn, tracker.filter); Display.getDefault().addFilter(SWT.MouseMove, tracker.filter); Display.getDefault().addFilter(SWT.MouseDown, tracker.filter); Display.getDefault().addFilter(SWT.MouseUp, tracker.filter); Display.getDefault().addFilter(SWT.Traverse, tracker.filter); } panel.composite.addDisposeListener(tracker); } public static void deactivate() { instance().deactivate(getActiveControl()); } public static int getLastTraverse() { return instance().lastTraverse; } public static int getMouseDownButton() { return instance().mouseButton; } public static Point getMouseDownLocation() { return instance().mouseDown; } public static boolean isFocusControl(Control control) { VControl focusControl = instance().focusControl; return (focusControl != null) && focusControl.isSameWidgetAs(control); } public static boolean isMouseDown() { return instance().mouseDown != null; } public static VControl getFocusControl() { return instance().focusControl; } public static VControl getActiveControl() { return instance().activeControl; } private static boolean setFocusFromPrev(Control control) { Control c = null; Composite parent = control.getParent(); if(parent == null) { c = control; } else { Control[] ca = parent.getTabList(); for(int i = 0; i < ca.length; i++) { if(ca[i] == control) { if(i == ca.length-1) { c = ca[0]; } else { c = ca[i+1]; } break; } } } if(c != null) { c.setFocus(); } return false; } private static boolean setFocusFromNext(Control control) { Control c = null; Composite parent = control.getParent(); if(parent == null) { c = control; } else { Control[] ca = parent.getTabList(); for(int i = 0; i < ca.length; i++) { if(ca[i] == control) { if(i == 0) { c = ca[ca.length-1]; } else { c = ca[i-1]; } break; } } } if(c != null) { c.setFocus(); } return false; } private static void setFocusToNext(Composite comp) { if(comp != null) { Composite parent = comp.getParent(); Control[] controls = parent.getTabList(); if(parent instanceof Shell) { for(int i = 0; i < controls.length; i++) { if(controls[i] == comp) { for(int j = 0; j < controls.length; j++) { i++; if(i > controls.length-1) { i = 0; } if(controls[i].forceFocus()) { return; } } } } } else { for(int i = 0; i < controls.length; i++) { if(controls[i] == comp) { for( ; i < controls.length-1; i++) { if(controls[i+1].forceFocus()) { return; } } setFocusToNext(comp.getParent()); } } } } } private static void setFocusToPrev(Composite comp) { if(comp != null) { Composite parent = comp.getParent(); Control[] controls = parent.getTabList(); if(parent instanceof Shell) { for(int i = 0; i < controls.length; i++) { if(controls[i] == comp) { for(int j = 0; j < controls.length; j++) { i--; if(i < 0) { i = controls.length-1; } if(controls[i].forceFocus()) { return; } } } } } else { for(int i = 0; i < controls.length; i++) { if(controls[i] == comp) { for( ; i > 0; i--) { if(controls[i-1].forceFocus()) { return; } } setFocusToPrev(comp.getParent()); } } } } } private static Boolean lock = new Boolean(true); static VTracker instance() { if(tracker == null) { synchronized (lock) { if(tracker == null) { tracker = new VTracker(); } } } return tracker; } private Map<Composite, VPanel> panels; private VControl activeControl = null; private Listener filter = new Listener() { public void handleEvent(Event event) { switch (event.type){ case SWT.Traverse: lastTraverse = event.detail; if(SWT.TRAVERSE_TAB_NEXT == event.detail || SWT.TRAVERSE_TAB_PREVIOUS == event.detail) { event.doit = true; if(focusControl != null) { focusControl.handleEvent(event); if(event.doit) { Composite comp = focusControl.getWidget(); if(SWT.TRAVERSE_TAB_NEXT == event.detail) { setFocusToNext(comp); } else { setFocusToPrev(comp); } } } else if(event.widget instanceof Control) { if(SWT.TRAVERSE_TAB_NEXT == event.detail) { if(setFocusFromPrev((Control) event.widget)){ event.type = SWT.None; event.doit = false; } } else { if(setFocusFromNext((Control) event.widget)){ event.type = SWT.None; event.doit = false; } } } } break; case SWT.FocusIn: setFocusControl(getVControl(event.widget)); break; case SWT.MouseDown: mouseButton = event.button; mouseDown = new Point(event.x, event.y); if(activeControl != null && activeControl.setState(VControl.STATE_MOUSE_DOWN, true)) { activeControl.redraw(); } break; case SWT.MouseMove: if(panels.containsKey(event.widget)) { VControl vcontrol = panels.get(event.widget).getControl(event.x, event.y, true); if(vcontrol != activeControl && (vcontrol == null || vcontrol.isEnabled())) { activate(vcontrol); } } else if(activeControl != null && event.widget != activeControl.getControl()) { activeControl.deactivate(); activeControl = null; } break; case SWT.MouseUp: mouseButton = -1; mouseDown = null; if(activeControl != null && activeControl.setState(VControl.STATE_MOUSE_DOWN, false)) { activeControl.redraw(); } break; } } }; public static VControl getVControl(Widget widget) { if(widget instanceof Shell) { Control[] ca = ((Shell) widget).getTabList(); if(ca.length > 0) { widget = ca[0]; } } Object o = widget.getData("cwt_vcontrol"); if(o instanceof VControl) { return (VControl) o; } return null; } private VControl focusControl = null; private boolean listening = false; private int mouseButton = -1; private Point mouseDown = null; private int lastTraverse = -1; private VTracker() { // singleton } void activate(VControl vcontrol) { if(activeControl != null && !activeControl.isDisposed()) { activeControl.deactivate(); } activeControl = vcontrol; if(activeControl != null) { activeControl.activate(); } } void deactivate(VControl vcontrol) { if(vcontrol != null) { if(!vcontrol.isDisposed()) { vcontrol.deactivate(); } if(activeControl == vcontrol) { activeControl = null; } } } private VControl getNewFocus(VPanel panel) { for(VControl child : panel.getChildren()) { if(!child.hasStyle(SWT.NO_FOCUS)) { if(child instanceof VPanel) { VControl newFocus = getNewFocus((VPanel) child); if(newFocus != null) { return newFocus; } } else { return child; } } } return null; } boolean setFocusControl(VControl control) { VControl newFocus = control; if(newFocus instanceof VPanel) { newFocus = getNewFocus((VPanel) newFocus); } else if(control != null && control.hasStyle(SWT.NO_FOCUS)) { return false; } if(newFocus == focusControl) { if(newFocus != null && !newFocus.isDisposed()) { newFocus.getControl().forceFocus(); } return true; } try { Display.getDefault().removeFilter(SWT.FocusIn, filter); VControl oldFocus = focusControl; if(oldFocus != null && !oldFocus.isDisposed()) { oldFocus.setFocus(false); } if(newFocus != null) { if(!newFocus.isDisposed() && newFocus.setFocus(true)) { newFocus.getControl().forceFocus(); } else { return false; } } focusControl = newFocus; if(newFocus != null) { newFocus.redraw(); } if(oldFocus != null && !oldFocus.isDisposed()) { oldFocus.redraw(); } notifyWidgetFocusListeners(focusControl, oldFocus); return true; } finally { Display.getDefault().addFilter(SWT.FocusIn, filter); } } private void notifyWidgetFocusListeners(VControl newFocus, VControl oldFocus) { if(newFocus != null && !newFocus.isSameWidgetAs(oldFocus)) { Widget widget = newFocus.getWidget(); if(widget.getData("cwt_focus") == null) { //$NON-NLS-1$ widget.setData("cwt_focus", this); //$NON-NLS-1$ Event event = new Event(); event.widget = widget; event.data = this; event.type = SWT.FocusIn; event.widget.notifyListeners(SWT.FocusIn, event); } } if(oldFocus != null && !oldFocus.isSameWidgetAs(newFocus)) { Widget widget = oldFocus.getWidget(); if(widget.getData("cwt_focus") != null) { //$NON-NLS-1$ widget.setData("cwt_focus", null); //$NON-NLS-1$ Event event = new Event(); event.widget = widget; event.data = this; event.type = SWT.FocusOut; event.widget.notifyListeners(SWT.FocusOut, event); } } } public void widgetDisposed(DisposeEvent e) { VTracker tracker = instance(); if(tracker.panels != null && tracker.panels.containsKey(e.widget)) { tracker.panels.remove(e.widget); if(tracker.panels.isEmpty()) { Display.getDefault().removeFilter(SWT.FocusIn, tracker.filter); Display.getDefault().removeFilter(SWT.MouseMove, tracker.filter); Display.getDefault().removeFilter(SWT.MouseDown, tracker.filter); Display.getDefault().removeFilter(SWT.MouseUp, tracker.filter); Display.getDefault().removeFilter(SWT.Traverse, tracker.filter); tracker.listening = false; if(activeControl != null) { Control control = activeControl.getControl(); if(control != null && !control.isDisposed()) { control.dispose(); } } tracker.panels = null; } } } }