Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 2e9d4f381c6378b11c18447d32929f81a1ed69eb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * Copyright (c) 2014 CEA and others.
 * 
 * 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:
 *   Christian W. Damus (CEA) - Initial API and implementation
 *
 */
package org.eclipse.papyrus.infra.gmfdiag.common.adapter;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
import org.eclipse.jface.action.IAction;
import org.eclipse.papyrus.infra.core.editor.reload.IReloadContextProvider;
import org.eclipse.papyrus.infra.gmfdiag.common.Activator;


/**
 * A {@linkplain IReloadContextProvider reload context provider} for nested diagram outline pages that records and restores the selection of
 * which presentation mode (tree outline or thumbnail overview) is active for each outline page. This implementation uses reflection to access
 * internals (non API) of the outline page. On any problem in initializing this reflective access, the adapter basically disables itself and
 * never participates in editor re-load, so that the system continues normally but with reduced functionality.
 */
class DiagramOutlineReloadContextProvider implements IReloadContextProvider {

	private static final int ID_OUTLINE = 0;

	private static final int ID_OVERVIEW = 1;

	private static final Class<?> diagramOutlinePage;

	private static final Method showPage;

	private static final Field showOutlineAction;

	static {
		Class<?> diagramOutlinePageClass = null;
		Method showPageMethod = null;
		Field showOutlineActionField = null;

		for(Class<?> next : DiagramEditor.class.getDeclaredClasses()) {
			if("DiagramOutlinePage".equals(next.getSimpleName())) { //$NON-NLS-1$
				diagramOutlinePageClass = next;

				try {
					showPageMethod = diagramOutlinePageClass.getDeclaredMethod("showPage", int.class); //$NON-NLS-1$
					showPageMethod.setAccessible(true);

					showOutlineActionField = diagramOutlinePageClass.getDeclaredField("showOutlineAction"); //$NON-NLS-1$
					showOutlineActionField.setAccessible(true);
				} catch (Exception e) {
					// Can't reflect?  Then abandon all hope
					Activator.log.error(e);
					diagramOutlinePageClass = null;
				}

				break;
			}
		}

		diagramOutlinePage = diagramOutlinePageClass;
		showPage = showPageMethod;
		showOutlineAction = showOutlineActionField;
	}

	private final Object diagramOutline;

	public DiagramOutlineReloadContextProvider(Object diagramOutline) {
		super();

		this.diagramOutline = diagramOutline;
	}

	@Override
	public Object createReloadContext() {
		return new ReloadContext(diagramOutline);
	}

	@Override
	public void restore(Object reloadContext) {
		((ReloadContext)reloadContext).restore(diagramOutline);
	}

	static boolean isDiagramOutline(Object o) {
		// If we couldn't reflect on DiagramOutline class, then we will never detect a diagram outline
		// instance, so we will never try to create an adapter, and all is safe.  The only consequence
		// will be that we don't get diagram outline state properly restored.  That's fine
		return (diagramOutlinePage != null) && diagramOutlinePage.isInstance(o);
	}

	//
	// Nested types
	//

	private static class ReloadContext {

		private final int pageID;

		public ReloadContext(Object diagramOutline) {
			super();

			try {
				this.pageID = ((IAction)showOutlineAction.get(diagramOutline)).isChecked() ? ID_OUTLINE : ID_OVERVIEW;
			} catch (IllegalAccessException e) {
				// We wouldn't be here if we couldn't make it accessible. Something is very wrong
				throw new Error(e);
			}
		}

		void restore(Object diagramOutline) {
			try {
				showPage.invoke(diagramOutline, pageID);
			} catch (IllegalAccessException e) {
				// We wouldn't be here if we couldn't make it accessible. Something is very wrong
				throw new Error(e);
			} catch (InvocationTargetException e) {
				Throwable target = e.getTargetException();
				if(target instanceof RuntimeException) {
					throw (RuntimeException)target;
				} else if(target instanceof Error) {
					throw (Error)target;
				} else {
					Activator.log.error(target);
				}
			}
		}
	}
}

Back to the top