001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package org.terracotta.dso.dialogs;
006:
007: import org.eclipse.core.resources.IProject;
008: import org.eclipse.core.runtime.CoreException;
009: import org.eclipse.debug.core.ILaunch;
010: import org.eclipse.debug.core.ILaunchConfiguration;
011: import org.eclipse.debug.core.model.IDebugTarget;
012: import org.eclipse.debug.core.model.IProcess;
013: import org.eclipse.debug.ui.DebugUITools;
014: import org.eclipse.jface.dialogs.MessageDialog;
015: import org.eclipse.swt.SWT;
016: import org.eclipse.swt.events.SelectionAdapter;
017: import org.eclipse.swt.events.SelectionEvent;
018: import org.eclipse.swt.events.SelectionListener;
019: import org.eclipse.swt.graphics.Rectangle;
020: import org.eclipse.swt.layout.GridData;
021: import org.eclipse.swt.layout.GridLayout;
022: import org.eclipse.swt.widgets.Button;
023: import org.eclipse.swt.widgets.Composite;
024: import org.eclipse.swt.widgets.Control;
025: import org.eclipse.swt.widgets.Shell;
026: import org.eclipse.swt.widgets.Tree;
027: import org.eclipse.swt.widgets.TreeItem;
028: import org.terracotta.dso.TcPlugin;
029: import org.terracotta.ui.util.SWTUtil;
030:
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.Map;
034:
035: /**
036: * <p>
037: * This dialog displays the set of Terracotta servers and DSO Application launches currently running and lets the user
038: * select the subset to either terminate or restart. Selecting/deselecting the Terracotta Server or DSO Applications
039: * nodes selects/deselects all child nodes. When all child nodes are selected/deselected, the parent node is made to
040: * match.
041: * <p>
042: * When the resultCode is set, after the dialog is closed, if the resultCode was not CONTINUE_INDEX the passed in map of
043: * server launches and the list of DSO Application launches are filtered according to users selection.
044: * <p>
045: * This dialog is used by ResourceDeltaVisitor after it notices the config file was saved.
046: *
047: * @see org.terracotta.dso.ResourceDeltaVisitor
048: * @author gkeim
049: */
050:
051: public class RelaunchDialog extends MessageDialog implements
052: SelectionListener {
053:
054: private IProject fProject;
055: private Tree fTree;
056: private TreeItem fServersItem;
057: private TreeItem fLaunchesItem;
058: private Map<String, ILaunch> fServerLaunches;
059: private List<ILaunch> fLaunches;
060:
061: private Button fDisableRelaunchQueryButton;
062:
063: private static String DISABLE_RELAUNCH_QUERY_MSG = "Don't bother me with this anymore";
064:
065: private static String TITLE = "Terracotta";
066: private static String MSG = "The configuration file changed. Relaunch all related launch targets?";
067:
068: public static int CONTINUE_ID = 0;
069: public static int TERMINATE_ID = CONTINUE_ID + 1;
070: public static int RESTART_ID = TERMINATE_ID + 1;
071:
072: private static String CONTINUE_LABEL = "Continue";
073: private static String TERMINATE_LABEL = "Terminate";
074: private static String RESTART_LABEL = "Restart";
075:
076: /*
077: * We attempt to show all the launch items by expanding the nodes and setting hints on the tree layout to display it's
078: * full content. This is the maximum number of items we'll try to accomodate in that way before the tree will scrolled
079: * vertically. This is all about the initial dialog size.
080: */
081: private static int MAX_VISIBLE_LAUNCH_ITEMS = 10;
082:
083: public RelaunchDialog(Shell shell, IProject project,
084: Map<String, ILaunch> serverLaunches, List<ILaunch> launches) {
085: super (shell, TITLE, null, MSG, MessageDialog.NONE,
086: new String[] { CONTINUE_LABEL, TERMINATE_LABEL,
087: RESTART_LABEL }, 0);
088: setShellStyle(getShellStyle() | SWT.RESIZE);
089: fProject = project;
090: fServerLaunches = serverLaunches;
091: fLaunches = launches;
092: }
093:
094: protected Control createDialogArea(Composite parent) {
095: parent.setLayout(new GridLayout());
096: return super .createDialogArea(parent);
097: }
098:
099: protected Control createCustomArea(Composite parent) {
100: Composite comp = new Composite(parent, SWT.NONE);
101: comp.setLayout(new GridLayout());
102: comp.setLayoutData(new GridData(GridData.FILL_BOTH));
103:
104: fTree = new Tree(comp, SWT.BORDER | SWT.MULTI | SWT.CHECK);
105: if (fServerLaunches.size() > 0) {
106: fServersItem = new TreeItem(fTree, SWT.NONE);
107: Iterator<String> iter = fServerLaunches.keySet().iterator();
108:
109: fServersItem.setText("Terracotta Servers");
110: fServersItem.setChecked(true);
111: while (iter.hasNext()) {
112: String name = iter.next();
113: ILaunch launch = fServerLaunches.get(name);
114: TreeItem serverLaunchItem = new TreeItem(fServersItem,
115: SWT.NONE);
116: serverLaunchItem.setData(launch);
117: serverLaunchItem.setText(computeName(launch));
118: serverLaunchItem.setChecked(true);
119: }
120: fServersItem.setExpanded(true);
121: }
122:
123: if (fLaunches.size() > 0) {
124: fLaunchesItem = new TreeItem(fTree, SWT.NONE);
125: fLaunchesItem.setText("DSO Applications");
126: fLaunchesItem.setChecked(true);
127:
128: Iterator<ILaunch> iter = fLaunches.iterator();
129: while (iter.hasNext()) {
130: ILaunch launch = iter.next();
131: String label = computeName(launch);
132: if (label == null) {
133: iter.remove();
134: continue;
135: }
136: TreeItem launchItem = new TreeItem(fLaunchesItem,
137: SWT.NONE);
138: launchItem.setData(launch);
139: launchItem.setText(label);
140: launchItem.setChecked(true);
141: }
142: fLaunchesItem.setExpanded(true);
143: }
144:
145: GridData gridData = new GridData(GridData.FILL_BOTH);
146: fTree.setLayoutData(gridData);
147: parent.pack();
148:
149: /*
150: * For some reason the above pack on the parent isn't causing the tree to display its full content, so the tree is
151: * walked and the union of all item bounds are computed and used as the size hint on the tree's grid data. We only
152: * try to initially expose up to MAX_VISIBLE_LAUNCH_ITEMS in the case someone has some outlandish number of servers
153: * and DSO apps running.
154: */
155: Rectangle r = new Rectangle(0, 0, 0, 0);
156: for (int i = 0; i < fTree.getItemCount(); i++) {
157: r = mergeBounds(fTree.getItem(i), r);
158: }
159:
160: gridData = new GridData(GridData.FILL_BOTH);
161: gridData.heightHint = Math.min(r.height, fTree.getItemHeight()
162: * MAX_VISIBLE_LAUNCH_ITEMS) + 10;
163: gridData.widthHint = Math.min(r.width, SWTUtil
164: .textColumnsToPixels(fTree, 100));
165: fTree.setLayoutData(gridData);
166:
167: fTree.addSelectionListener(this );
168:
169: fDisableRelaunchQueryButton = new Button(comp, SWT.CHECK);
170: fDisableRelaunchQueryButton.setLayoutData(new GridData());
171: fDisableRelaunchQueryButton.setText(DISABLE_RELAUNCH_QUERY_MSG);
172: fDisableRelaunchQueryButton.setSelection(!TcPlugin.getDefault()
173: .getQueryRestartOption(fProject));
174: fDisableRelaunchQueryButton
175: .addSelectionListener(new SelectionAdapter() {
176: public void widgetSelected(SelectionEvent e) {
177: boolean disableQueryRelaunch = fDisableRelaunchQueryButton
178: .getSelection();
179: TcPlugin.getDefault().setQueryRestartOption(
180: fProject, !disableQueryRelaunch);
181: }
182: });
183:
184: return parent;
185: }
186:
187: protected void setReturnCode(int code) {
188: super .setReturnCode(code);
189:
190: if (code != CONTINUE_ID) {
191: if (fServersItem != null) {
192: int serverLaunchCount = fServersItem.getItemCount();
193: for (int i = 0; i < serverLaunchCount; i++) {
194: TreeItem item = fServersItem.getItem(i);
195: if (!item.getChecked()) {
196: fServerLaunches.values().remove(item.getData());
197: }
198: }
199: }
200:
201: if (fLaunchesItem != null) {
202: int launchCount = fLaunchesItem.getItemCount();
203: for (int i = 0; i < launchCount; i++) {
204: TreeItem item = fLaunchesItem.getItem(i);
205: if (!item.getChecked()) {
206: fLaunches.remove(item.getData());
207: }
208: }
209: }
210: }
211: }
212:
213: private boolean allChildrenChecked(TreeItem item) {
214: int count = item.getItemCount();
215: for (int i = 0; i < count; i++) {
216: if (!item.getItem(i).getChecked()) {
217: return false;
218: }
219: }
220: return true;
221: }
222:
223: private void handleCheckChanged(TreeItem item) {
224: TreeItem parentItem = item.getParentItem();
225: boolean isChecked = item.getChecked();
226: if (parentItem == null) {
227: for (int i = 0; i < item.getItemCount(); i++) {
228: TreeItem child = item.getItem(i);
229: child.setChecked(isChecked);
230: }
231: } else {
232: if (!isChecked) {
233: parentItem.setChecked(false);
234: } else if (allChildrenChecked(parentItem)) {
235: parentItem.setChecked(true);
236: }
237: }
238: }
239:
240: public void widgetSelected(SelectionEvent e) {
241: if (e.detail == SWT.CHECK) {
242: handleCheckChanged((TreeItem) e.item);
243: }
244: }
245:
246: public void widgetDefaultSelected(SelectionEvent e) {
247: /**/
248: }
249:
250: private static Rectangle mergeBounds(TreeItem item, Rectangle r) {
251: r = r.union(item.getBounds());
252: for (int i = 0; i < item.getItemCount(); i++) {
253: r = mergeBounds(item.getItem(i), r);
254: }
255: return r;
256: }
257:
258: private static IProcess getProcess(ILaunch launch) {
259: IDebugTarget debugTarget = launch.getDebugTarget();
260: if (debugTarget != null) {
261: return debugTarget.getProcess();
262: }
263:
264: IProcess[] processes = launch.getProcesses();
265: if (processes != null && processes.length > 0) {
266: return processes[0];
267: }
268:
269: return null;
270: }
271:
272: protected String computeName(ILaunch launch) {
273: String label = null;
274: IProcess process = getProcess(launch);
275: if (process == null) {
276: return null;
277: }
278:
279: ILaunchConfiguration config = process.getLaunch()
280: .getLaunchConfiguration();
281: label = process.getAttribute(IProcess.ATTR_PROCESS_LABEL);
282: if (label == null) {
283: if (config == null) {
284: label = process.getLabel();
285: } else {
286: // check if PRIVATE config
287: if (DebugUITools.isPrivate(config)) {
288: label = process.getLabel();
289: } else {
290: String type = null;
291: try {
292: type = config.getType().getName();
293: } catch (CoreException e) {/**/
294: }
295: StringBuffer buffer = new StringBuffer();
296: buffer.append(config.getName());
297: if (type != null) {
298: buffer.append(" ["); //$NON-NLS-1$
299: buffer.append(type);
300: buffer.append("] "); //$NON-NLS-1$
301: }
302: buffer.append(process.getLabel());
303: label = buffer.toString();
304: }
305: }
306: }
307:
308: return label;
309: }
310: }
|