/* * Copyright (c) 2012, grossmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the jo-widgets.org nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL jo-widgets.org BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ package org.jowidgets.addons.widgets.ole.impl.swt.common; import java.io.File; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.internal.ole.win32.IDispatch; import org.eclipse.swt.internal.ole.win32.IUnknown; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.ole.win32.OLE; import org.eclipse.swt.ole.win32.OleAutomation; import org.eclipse.swt.ole.win32.OleControlSite; import org.eclipse.swt.ole.win32.OleEvent; import org.eclipse.swt.ole.win32.OleFrame; import org.eclipse.swt.ole.win32.OleListener; import org.eclipse.swt.ole.win32.Variant; import org.eclipse.swt.widgets.Composite; import org.jowidgets.addons.widgets.ole.api.IInvocationParameter; import org.jowidgets.addons.widgets.ole.api.IOleAutomation; import org.jowidgets.addons.widgets.ole.api.IOleControl; import org.jowidgets.addons.widgets.ole.api.IOleControlSetupBuilder; import org.jowidgets.addons.widgets.ole.api.IOleEvent; import org.jowidgets.addons.widgets.ole.api.IOleEventListener; import org.jowidgets.addons.widgets.ole.api.OleCommand; import org.jowidgets.addons.widgets.ole.api.OleCommandOption; import org.jowidgets.api.widgets.IControl; import org.jowidgets.common.widgets.controller.IFocusListener; import org.jowidgets.spi.impl.controller.FocusObservable; import org.jowidgets.tools.widgets.wrapper.ControlWrapper; import org.jowidgets.util.Assert; import org.jowidgets.util.Tuple; class OleControlImpl extends ControlWrapper implements IOleControl { private final FocusObservable focusObservable; private final FocusListenerAdapter focusListenerAdapter; private final OleFrame oleFrame; private final OleEventObservable oleEventObservable; private OleControlSite oleControlSiteLazy; private OleAutomationImpl oleAutomationLazy; private boolean enabled; OleControlImpl(final IControl control, final Composite swtComposite, final IOleControlSetupBuilder<?> setup) { super(control); swtComposite.setLayout(new FillLayout()); this.oleEventObservable = new OleEventObservable(); this.oleFrame = new OleFrame(swtComposite, SWT.NONE); this.focusObservable = new FocusObservable(); this.focusListenerAdapter = new FocusListenerAdapter(); this.enabled = true; } @Override public void execute(final OleCommand command, final Object in, final OleCommandOption... options) { Assert.paramNotNull(command, "command"); final OleControlSite controlSite = getOleControlSite(); final int commandId = getCommandId(command); final Variant variantIn = in != null ? createVariant(in) : null; controlSite.exec(commandId, getCommandOptions(options), variantIn, null); } @Override public void setDocument(final String progId) { setDocument(progId, null); } @Override public void setDocument(final File file) { setDocument(null, file); } @Override public void setDocument(final String progId, final File file) { if (oleControlSiteLazy != null) { clearDocument(); } if (progId != null && file != null) { oleControlSiteLazy = new OleControlSite(oleFrame, SWT.NONE, progId, file); } else if (progId != null) { oleControlSiteLazy = new OleControlSite(oleFrame, SWT.NONE, progId); } else if (file != null) { oleControlSiteLazy = new OleControlSite(oleFrame, SWT.NONE, file); } if (oleControlSiteLazy != null) { if (!enabled) { oleControlSiteLazy.setEnabled(enabled); } oleControlSiteLazy.addFocusListener(focusListenerAdapter); oleControlSiteLazy.doVerb(OLE.OLEIVERB_INPLACEACTIVATE); } oleEventObservable.setSwtOleControlSite(oleControlSiteLazy); } @Override public void clearDocument() { if (oleAutomationLazy != null) { oleAutomationLazy.dispose(); } getOleControlSite().dispose(); oleControlSiteLazy = null; oleAutomationLazy = null; } @Override public boolean saveCurrentDocument(final File file, final boolean includeOleInfo) { return getOleControlSite().save(file, includeOleInfo); } @Override public boolean isDirty() { if (oleControlSiteLazy != null) { return oleControlSiteLazy.isDirty(); } return false; } @Override public boolean isDisposed() { if (oleControlSiteLazy != null) { return oleControlSiteLazy.isDisposed(); } return true; } @Override public IOleAutomation getAutomation() { if (oleAutomationLazy == null) { oleAutomationLazy = new OleAutomationImpl(new OleAutomation(getOleControlSite())); } return oleAutomationLazy; } @Override public void addEventListener(final int eventID, final IOleEventListener listener) { oleEventObservable.addEventListener(eventID, listener); } @Override public void removeEventListener(final int eventID, final IOleEventListener listener) { oleEventObservable.removeEventListener(eventID, listener); } @Override public void addFocusListener(final IFocusListener listener) { focusObservable.addFocusListener(listener); } @Override public void removeFocusListener(final IFocusListener listener) { focusObservable.removeFocusListener(listener); } @Override public void setEnabled(final boolean enabled) { if (oleControlSiteLazy != null) { oleControlSiteLazy.setEnabled(enabled); } this.enabled = enabled; } private OleControlSite getOleControlSite() { if (oleControlSiteLazy == null) { throw new IllegalStateException("There is no document set"); } return oleControlSiteLazy; } private int getCommandOptions(final OleCommandOption... options) { int result = 0; if (options != null) { final Set<OleCommandOption> optionsSet = new HashSet<OleCommandOption>(Arrays.asList(options)); if (optionsSet.contains(OleCommandOption.DODEFAULT)) { result = result | OLE.OLECMDEXECOPT_DODEFAULT; } if (optionsSet.contains(OleCommandOption.DONTPROMPTUSER)) { result = result | OLE.OLECMDEXECOPT_DONTPROMPTUSER; } if (optionsSet.contains(OleCommandOption.PROMPTUSER)) { result = result | OLE.OLECMDEXECOPT_PROMPTUSER; } if (optionsSet.contains(OleCommandOption.SHOWHELP)) { result = result | OLE.OLECMDEXECOPT_SHOWHELP; } } return result; } private int getCommandId(final OleCommand command) { if (command == OleCommand.OPEN) { return OLE.OLECMDID_OPEN; } else if (command == OleCommand.NEW) { return OLE.OLECMDID_NEW; } else if (command == OleCommand.SAVE) { return OLE.OLECMDID_SAVE; } else if (command == OleCommand.SAVEAS) { return OLE.OLECMDID_SAVEAS; } else if (command == OleCommand.SAVECOPYAS) { return OLE.OLECMDID_SAVECOPYAS; } else if (command == OleCommand.PRINT) { return OLE.OLECMDID_PRINT; } else if (command == OleCommand.PRINTPREVIEW) { return OLE.OLECMDID_PRINTPREVIEW; } else if (command == OleCommand.PAGESETUP) { return OLE.OLECMDID_PAGESETUP; } else if (command == OleCommand.SPELL) { return OLE.OLECMDID_SPELL; } else if (command == OleCommand.PROPERTIES) { return OLE.OLECMDID_PROPERTIES; } else if (command == OleCommand.CUT) { return OLE.OLECMDID_CUT; } else if (command == OleCommand.COPY) { return OLE.OLECMDID_COPY; } else if (command == OleCommand.PASTE) { return OLE.OLECMDID_PASTE; } else if (command == OleCommand.PASTERSPECIAL) { return OLE.OLECMDID_PASTESPECIAL; } else if (command == OleCommand.UNDO) { return OLE.OLECMDID_UNDO; } else if (command == OleCommand.REDO) { return OLE.OLECMDID_REDO; } else if (command == OleCommand.SELECTALL) { return OLE.OLECMDID_SELECTALL; } else if (command == OleCommand.CLEARSELECTION) { return OLE.OLECMDID_CLEARSELECTION; } else if (command == OleCommand.ZOOM) { return OLE.OLECMDID_ZOOM; } else if (command == OleCommand.GETZOOMRANGE) { return OLE.OLECMDID_GETZOOMRANGE; } else if (command == OleCommand.UPDATECOMMANDS) { return OLE.OLECMDID_UPDATECOMMANDS; } else if (command == OleCommand.REFRESH) { return OLE.OLECMDID_REFRESH; } else if (command == OleCommand.STOP) { return OLE.OLECMDID_STOP; } else if (command == OleCommand.HIDETOOLBARS) { return OLE.OLECMDID_HIDETOOLBARS; } else if (command == OleCommand.SETPROGRESSMAX) { return OLE.OLECMDID_SETPROGRESSMAX; } else if (command == OleCommand.SETPROGRESSPOS) { return OLE.OLECMDID_SETPROGRESSPOS; } else if (command == OleCommand.SETPROGRESSTEXT) { return OLE.OLECMDID_SETPROGRESSTEXT; } else if (command == OleCommand.SETTITLE) { return OLE.OLECMDID_SETTITLE; } else if (command == OleCommand.SETDOWNLOADSTATE) { return OLE.OLECMDID_SETDOWNLOADSTATE; } else if (command == OleCommand.STOPDOWNLOAD) { return OLE.OLECMDID_STOPDOWNLOAD; } else { throw new IllegalArgumentException("Command '" + command + "' is not supported."); } } private Object getVariantResult(final Variant variant) { if (variant == null) { return null; } else if (OLE.VT_BOOL == variant.getType()) { return variant.getBoolean(); } else if (OLE.VT_R4 == variant.getType()) { return variant.getFloat(); } else if (OLE.VT_R8 == variant.getType()) { return variant.getDouble(); } else if (OLE.VT_I4 == variant.getType()) { return variant.getInt(); } else if (OLE.VT_I2 == variant.getType()) { return variant.getShort(); } else if (OLE.VT_BSTR == variant.getType()) { return variant.getString(); } else if (OLE.VT_BSTR == variant.getType()) { return variant.getString(); } else if (OLE.VT_DISPATCH == variant.getType()) { //TODO MG dispose this, when context will be disposed return new OleAutomationImpl(variant.getAutomation()); } return variant; } private Variant createVariant(final Object object) { if (object instanceof String) { return new Variant((String) object); } else if (object instanceof Integer) { return new Variant(((Integer) object).intValue()); } else if (object instanceof Long) { return new Variant(((Long) object).longValue()); } else if (object instanceof Double) { return new Variant(((Double) object).doubleValue()); } else if (object instanceof Float) { return new Variant(((Float) object).floatValue()); } else if (object instanceof Short) { return new Variant(((Short) object).shortValue()); } else if (object instanceof Boolean) { return new Variant(((Boolean) object).booleanValue()); } else if (object instanceof Byte) { return new Variant(((Byte) object).byteValue()); } else if (object instanceof Character) { return new Variant(((Character) object).charValue()); } else if (object instanceof IDispatch) { return new Variant(((IDispatch) object)); } else if (object instanceof IUnknown) { return new Variant(((IUnknown) object)); } else { throw new IllegalArgumentException("parameter type '" + object.getClass().getName() + "' is not supported"); } } private final class FocusListenerAdapter implements FocusListener { @Override public void focusLost(final FocusEvent e) { focusObservable.focusLost(); } @Override public void focusGained(final FocusEvent e) { focusObservable.focusGained(); } } private final class OleAutomationImpl implements IOleAutomation { private final OleAutomation oleAutomation; private final OleEventObservable oleEventObservable; OleAutomationImpl(final OleAutomation oleAutomation) { Assert.paramNotNull(oleAutomation, "oleAutomation"); this.oleAutomation = oleAutomation; this.oleEventObservable = new OleEventObservable(oleAutomation); this.oleEventObservable.setSwtOleControlSite(getOleControlSite()); } @SuppressWarnings("unchecked") @Override public <RESULT_TYPE> RESULT_TYPE invoke(final String methodName, final IInvocationParameter... parameters) { Assert.paramNotEmpty(methodName, "methodName"); Assert.paramNotNull(parameters, "parameters"); final String[] parameterNames = new String[parameters.length]; final Variant[] variants = new Variant[parameters.length]; int index = 0; for (final IInvocationParameter parameter : parameters) { parameterNames[index] = parameter.getParameterName(); variants[index] = createVariant(parameter.getParameter()); index++; } final int[] paramterNamesIds = oleAutomation.getIDsOfNames(parameterNames); final int[] methodNameIds = oleAutomation.getIDsOfNames(new String[] {methodName}); return (RESULT_TYPE) getVariantResult(oleAutomation.invoke(methodNameIds[0], variants, paramterNamesIds)); } @Override public boolean setProperty(final String propertyName, final Object... parameters) { Assert.paramNotEmpty(parameters, "parameters"); final int[] propertyNameIds = oleAutomation.getIDsOfNames(new String[] {propertyName}); if (propertyNameIds != null && propertyNameIds.length == 1) { if (parameters.length > 1) { final Variant[] variants = new Variant[parameters.length]; for (int i = 0; i < parameters.length; i++) { variants[i] = createVariant(parameters[i]); } return oleAutomation.setProperty(propertyNameIds[0], variants); } else { return oleAutomation.setProperty(propertyNameIds[0], createVariant(parameters[0])); } } else { return false; } } @SuppressWarnings("unchecked") @Override public <RESULT_TYPE> RESULT_TYPE getProperty(final String propertyName, final Object... parameters) { final int[] propertyNameIds = oleAutomation.getIDsOfNames(new String[] {propertyName}); if (propertyNameIds != null && propertyNameIds.length == 1) { if (parameters == null || parameters.length == 0) { return (RESULT_TYPE) getVariantResult(oleAutomation.getProperty(propertyNameIds[0])); } else if (parameters.length > 1) { final Variant[] variants = new Variant[parameters.length]; for (int i = 0; i < parameters.length; i++) { variants[i] = createVariant(parameters[i]); } return (RESULT_TYPE) getVariantResult(oleAutomation.getProperty(propertyNameIds[0], variants)); } else { return (RESULT_TYPE) getVariantResult( oleAutomation.getProperty(propertyNameIds[0], new Variant[] {createVariant(parameters[0])})); } } else { throw new IllegalArgumentException("Property name '" + propertyName + "' is unknown"); } } @Override public void addEventListener(final int eventID, final IOleEventListener listener) { oleEventObservable.addEventListener(eventID, listener); } @Override public void removeEventListener(final int eventID, final IOleEventListener listener) { oleEventObservable.removeEventListener(eventID, listener); } @Override public String getTypeInfo() { return OleAutomationTypeInfoUtil.getTypeInfo(oleAutomation); } @Override public void dispose() { oleEventObservable.dispose(); oleAutomation.dispose(); } } final class OleEventObservable { private final Map<Integer, Tuple<OleListener, Set<IOleEventListener>>> listenersMap; private final OleAutomation oleAutomation; private OleControlSite oleControlSite; OleEventObservable() { this(null); } OleEventObservable(final OleAutomation oleAutomation) { this.oleAutomation = oleAutomation; this.listenersMap = new HashMap<Integer, Tuple<OleListener, Set<IOleEventListener>>>(); } void setSwtOleControlSite(final OleControlSite oleControlSite) { unregisterListners(); this.oleControlSite = oleControlSite; for (final Entry<Integer, Tuple<OleListener, Set<IOleEventListener>>> entry : listenersMap.entrySet()) { final int eventId = entry.getKey().intValue(); final OleListener oleListener = entry.getValue().getFirst(); if (oleControlSite != null) { if (oleAutomation != null) { this.oleControlSite.addEventListener(oleAutomation, eventId, oleListener); } else { this.oleControlSite.addEventListener(eventId, oleListener); } } } } void addEventListener(final int eventId, final IOleEventListener listener) { Assert.paramNotNull(listener, "listener"); Tuple<OleListener, Set<IOleEventListener>> tuple = listenersMap.get(Integer.valueOf(eventId)); if (tuple == null) { final Set<IOleEventListener> listeners = new LinkedHashSet<IOleEventListener>(); final OleListenerAdapter listenerAdapter = new OleListenerAdapter(listeners); tuple = new Tuple<OleListener, Set<IOleEventListener>>(listenerAdapter, listeners); listenersMap.put(Integer.valueOf(eventId), tuple); if (this.oleControlSite != null) { if (oleAutomation != null) { this.oleControlSite.addEventListener(oleAutomation, eventId, listenerAdapter); } else { this.oleControlSite.addEventListener(eventId, listenerAdapter); } } } tuple.getSecond().add(listener); } void removeEventListener(final int eventId, final IOleEventListener listener) { Assert.paramNotNull(listener, "listener"); final Tuple<OleListener, Set<IOleEventListener>> tuple = listenersMap.get(Integer.valueOf(eventId)); if (tuple != null) { final Set<IOleEventListener> listners = tuple.getSecond(); listners.remove(listener); if (listners.size() == 0) { listenersMap.remove(Integer.valueOf(eventId)); if (this.oleControlSite != null) { if (oleAutomation != null) { this.oleControlSite.removeEventListener(oleAutomation, eventId, tuple.getFirst()); } else { this.oleControlSite.removeEventListener(eventId, tuple.getFirst()); } } } } } void unregisterListners() { for (final Entry<Integer, Tuple<OleListener, Set<IOleEventListener>>> entry : listenersMap.entrySet()) { final int eventId = entry.getKey().intValue(); final OleListener oleListener = entry.getValue().getFirst(); if (oleControlSite != null) { if (oleAutomation != null) { oleControlSite.removeEventListener(oleAutomation, eventId, oleListener); } else { oleControlSite.removeEventListener(eventId, oleListener); } } } } void dispose() { unregisterListners(); listenersMap.clear(); } private final class OleListenerAdapter implements OleListener { private final Set<IOleEventListener> listeners; private OleListenerAdapter(final Set<IOleEventListener> listeners) { this.listeners = listeners; } @Override public void handleEvent(final OleEvent event) { for (final IOleEventListener listener : new LinkedList<IOleEventListener>(listeners)) { listener.handleEvent(new OleEventImpl(event)); } } } } private final class OleEventImpl implements IOleEvent { private final Object[] arguments; private OleEventImpl(final OleEvent event) { final Variant[] variants = event.arguments; if (variants != null) { arguments = new Object[variants.length]; for (int i = 0; i < variants.length; i++) { arguments[i] = getVariantResult(variants[i]); } } else { arguments = new Object[0]; } } @Override public int getArgumentCount() { return arguments.length; } @SuppressWarnings("unchecked") @Override public <RESULT_TYPE> RESULT_TYPE getArgument(final int nr) { return (RESULT_TYPE) arguments[nr]; } @Override public Object[] getArguments() { return arguments; } @Override public String toString() { return "OleEventImpl [arguments=" + Arrays.toString(arguments) + "]"; } } }