1 /******************************************************************************* 2 * Copyright (c) 2000, 2020 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Paul Pazderski - Bug 251642: show process termination time 14 *******************************************************************************/ 15 package org.eclipse.debug.internal.ui.preferences; 16 17 18 import java.text.DateFormat; 19 import java.text.ParseException; 20 import java.util.Arrays; 21 import java.util.Date; 22 import java.util.regex.Matcher; 23 import java.util.regex.Pattern; 24 25 import org.eclipse.debug.core.DebugPlugin; 26 import org.eclipse.debug.core.model.IDebugElement; 27 import org.eclipse.debug.core.model.IProcess; 28 import org.eclipse.debug.internal.ui.IDebugHelpContextIds; 29 import org.eclipse.debug.internal.ui.SWTFactory; 30 import org.eclipse.jface.resource.JFaceResources; 31 import org.eclipse.swt.SWT; 32 import org.eclipse.swt.custom.BidiSegmentEvent; 33 import org.eclipse.swt.custom.BidiSegmentListener; 34 import org.eclipse.swt.custom.StyledText; 35 import org.eclipse.swt.graphics.Font; 36 import org.eclipse.swt.layout.GridData; 37 import org.eclipse.swt.widgets.Composite; 38 import org.eclipse.swt.widgets.Control; 39 import org.eclipse.swt.widgets.Text; 40 import org.eclipse.ui.PlatformUI; 41 import org.eclipse.ui.dialogs.PropertyPage; 42 43 public class ProcessPropertyPage extends PropertyPage { 44 45 private static Font fHeadingFont = JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT); 46 47 /** 48 * Constructor for ProcessPropertyPage 49 */ ProcessPropertyPage()50 public ProcessPropertyPage() { 51 super(); 52 } 53 54 @Override createContents(Composite ancestor)55 protected Control createContents(Composite ancestor) { 56 noDefaultAndApplyButton(); 57 Composite parent = SWTFactory.createComposite(ancestor, ancestor.getFont(), 1, 1, GridData.FILL_BOTH); 58 59 IProcess proc = getProcess(); 60 61 // create the process launch time section 62 SWTFactory.createLabel(parent, DebugPreferencesMessages.ProcessPropertyPage_0, fHeadingFont, 1); 63 Text text = SWTFactory.createText(parent, SWT.READ_ONLY, 1); 64 ((GridData)text.getLayoutData()).horizontalIndent = 10; 65 PlatformUI.getWorkbench().getHelpSystem().setHelp(text, IDebugHelpContextIds.PROCESS_PAGE_RUN_AT); 66 text.setText(getLaunchTimeText(proc)); 67 text.setBackground(parent.getBackground()); 68 SWTFactory.createVerticalSpacer(parent, 2); 69 70 // create the process terminate time section 71 SWTFactory.createLabel(parent, DebugPreferencesMessages.ProcessPropertyPage_10, fHeadingFont, 1); 72 text = SWTFactory.createText(parent, SWT.READ_ONLY, 1); 73 ((GridData) text.getLayoutData()).horizontalIndent = 10; 74 PlatformUI.getWorkbench().getHelpSystem().setHelp(text, IDebugHelpContextIds.PROCESS_PAGE_TERMINATE_AT); 75 text.setText(getTerminateTimeText(proc)); 76 text.setBackground(parent.getBackground()); 77 SWTFactory.createVerticalSpacer(parent, 2); 78 79 //create the path name section 80 SWTFactory.createLabel(parent, DebugPreferencesMessages.ProcessPropertyPage_1, fHeadingFont, 1); 81 text = SWTFactory.createText(parent, SWT.WRAP | SWT.READ_ONLY, 1); 82 ((GridData)text.getLayoutData()).horizontalIndent = 10; 83 text.setText(getPathText(proc)); 84 text.setBackground(parent.getBackground()); 85 SWTFactory.createVerticalSpacer(parent, 2); 86 87 //create working directory section 88 SWTFactory.createLabel(parent, DebugPreferencesMessages.ProcessPropertyPage_6, fHeadingFont, 1); 89 text = SWTFactory.createText(parent, SWT.WRAP | SWT.READ_ONLY, 1); 90 ((GridData)text.getLayoutData()).horizontalIndent = 10; 91 text.setText(getWorkingDirectory(proc)); 92 text.setBackground(parent.getBackground()); 93 SWTFactory.createVerticalSpacer(parent, 2); 94 95 //create command line section 96 SWTFactory.createLabel(parent, DebugPreferencesMessages.ProcessPropertyPage_Command_Line__1, fHeadingFont, 1); 97 StyledText styledText = SWTFactory.createStyledText(parent, 98 SWT.WRAP | SWT.READ_ONLY | SWT.BORDER | SWT.V_SCROLL, 99 1, 100 convertWidthInCharsToPixels(13), 101 convertHeightInCharsToPixels(10), 102 GridData.FILL_BOTH); 103 styledText.setBackground(parent.getBackground()); 104 ((GridData)styledText.getLayoutData()).horizontalIndent = 10; 105 String commandLineText = DebugPreferencesMessages.ProcessPropertyPage_5; 106 if (proc != null) { 107 commandLineText = proc.getAttribute(IProcess.ATTR_CMDLINE); 108 String[] arguments = DebugPlugin.parseArguments(commandLineText); 109 int count = arguments.length; 110 if (count > 1) { 111 // render as one argument per line, but don't copy line delimiters to clipboard: 112 final int[] segments = new int[count - 1]; 113 commandLineText = DebugPlugin.renderArguments(arguments, segments); 114 115 styledText.addBidiSegmentListener(new BidiSegmentListener() { 116 @Override 117 public void lineGetSegments(BidiSegmentEvent event) { 118 int offset = event.lineOffset; 119 int end = offset + event.lineText.length(); 120 121 // extract segments for the current line: 122 int iStart = Arrays.binarySearch(segments, offset); 123 if (iStart < 0) { 124 iStart = -iStart - 1; 125 } 126 int i = iStart; 127 while (i < segments.length && segments[i] < end) { 128 i++; 129 } 130 int n = i - iStart; 131 if (n > 0) { 132 if (n == segments.length) { 133 event.segments = segments; 134 } else { 135 int[] lineSegments = new int[n]; 136 System.arraycopy(segments, iStart, lineSegments, 0, n); 137 event.segments = lineSegments; 138 } 139 final char[] chars = new char[n]; 140 Arrays.fill(chars, '\n'); 141 event.segmentsChars = chars; 142 } 143 } 144 }); 145 } 146 } 147 if(commandLineText != null) { 148 styledText.setText(commandLineText); 149 } 150 151 //create environment section 152 SWTFactory.createLabel(parent, DebugPreferencesMessages.ProcessPropertyPage_7, fHeadingFont, 1); 153 text = SWTFactory.createText(parent, 154 SWT.H_SCROLL | SWT.READ_ONLY | SWT.BORDER | SWT.V_SCROLL, 155 1, 156 convertWidthInCharsToPixels(13), 157 convertHeightInCharsToPixels(8), 158 GridData.FILL_BOTH); 159 text.setBackground(parent.getBackground()); 160 ((GridData)text.getLayoutData()).horizontalIndent = 10; 161 text.setText(getEnvironment(proc)); 162 163 setTitle(DebugPreferencesMessages.ProcessPropertyPage_2); 164 return parent; 165 } 166 167 /** 168 * Gets the process from the selected element 169 * @return the process or null if the element is not a process 170 * 171 * @since 3.2 172 */ getProcess()173 private IProcess getProcess() { 174 IProcess proc = null; 175 Object obj = getElement(); 176 if (obj instanceof IDebugElement) { 177 obj = ((IDebugElement)obj).getDebugTarget().getProcess(); 178 } 179 if (obj instanceof IProcess) { 180 proc = ((IProcess)obj); 181 } 182 return proc; 183 } 184 185 /** 186 * returns the path text 187 * @param proc the process to extract the path text from 188 * @return the path text or a message indicating no path text available 189 * 190 * @see DebugPlugin#ATTR_PATH 191 * @since 3.2 192 */ getPathText(IProcess proc)193 private String getPathText(IProcess proc) { 194 String text = DebugPreferencesMessages.ProcessPropertyPage_3; 195 if(proc != null) { 196 String tmp = proc.getAttribute(DebugPlugin.ATTR_PATH); 197 if(tmp != null) { 198 return tmp; 199 } 200 tmp = proc.getLabel(); 201 // TODO remove this ugly workaround after removing start time from process label 202 // in jdt 203 int idx = tmp.lastIndexOf('('); 204 if(idx < 0) { 205 idx = tmp.length(); 206 } 207 text = tmp.substring(0, idx); 208 } 209 return text; 210 } 211 212 /** 213 * Try to get the launch time for the process. 214 * 215 * @param proc the process to get launch time for 216 * @return the launch time or default replacement 217 * @since 3.2 218 */ getLaunchTimeText(IProcess proc)219 private String getLaunchTimeText(IProcess proc) { 220 String text = getTimeFromAttribute(proc, DebugPlugin.ATTR_LAUNCH_TIMESTAMP); 221 if (text != null) { 222 return text; 223 } 224 // TODO remove this parsing when launch time is no fixed part of label anymore 225 Pattern pattern = Pattern.compile("\\(.*\\)"); //$NON-NLS-1$ 226 Matcher matcher = pattern.matcher(proc.getLabel()); 227 if (matcher.find()) { 228 text = matcher.group(0); 229 } 230 if (text != null) { 231 return text; 232 } 233 return DebugPreferencesMessages.ProcessPropertyPage_4; 234 } 235 236 /** 237 * Try to get the terminate time for the process. 238 * 239 * @param proc the process to get terminate time for 240 * @return the terminate time or default replacement 241 */ getTerminateTimeText(IProcess proc)242 private String getTerminateTimeText(IProcess proc) { 243 String text = getTimeFromAttribute(proc, DebugPlugin.ATTR_TERMINATE_TIMESTAMP); 244 return text != null ? text : DebugPreferencesMessages.ProcessPropertyPage_4; 245 } 246 247 /** 248 * Try to process launch timestamp attribute. 249 * 250 * @param proc the process to check 251 * @param attr the process attribute to check for timestamp 252 * @return the timestamp string or <code>null</code> 253 * @since 3.2 254 */ getTimeFromAttribute(IProcess proc, String attr)255 private String getTimeFromAttribute(IProcess proc, String attr) { 256 if (proc == null || attr == null) { 257 return null; 258 } 259 String time = proc.getAttribute(attr); 260 if (time == null) { 261 return null; 262 } 263 // check to see if the date/time is just the raw long (as a string) 264 try { 265 long l = Long.parseLong(time); 266 return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(new Date(l)); 267 } catch (NumberFormatException nfe) { 268 // not a number try to format the string so it always looks the same 269 try { 270 Date fdate = DateFormat.getInstance().parse(time); 271 return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(fdate); 272 } catch (ParseException pe) { 273 // couldn't do it, return the raw string 274 } 275 } 276 return time; 277 } 278 279 /** 280 * Initializes the text to be displayed in the environment text widget 281 * @param proc 282 * @return the environment path or a default string never <code>null</code> 283 * 284 * @see DebugPlugin#ATTR_ENVIRONMENT 285 * @since 3.8 286 */ getEnvironment(IProcess proc)287 String getEnvironment(IProcess proc) { 288 String env = DebugPreferencesMessages.ProcessPropertyPage_8; 289 if(proc != null) { 290 String tmp = proc.getAttribute(DebugPlugin.ATTR_ENVIRONMENT); 291 if(tmp != null) { 292 return tmp; 293 } 294 } 295 return env; 296 } 297 298 /** 299 * Initializes the text to be displayed in the working directory text widget 300 * 301 * @param proc 302 * @return the text to display or a default {@link String} never <code>null</code> 303 * 304 * @see DebugPlugin#ATTR_WORKING_DIRECTORY 305 * @since 3.8 306 */ getWorkingDirectory(IProcess proc)307 String getWorkingDirectory(IProcess proc) { 308 String wd = DebugPreferencesMessages.ProcessPropertyPage_9; 309 if(proc != null) { 310 String tmp = proc.getAttribute(DebugPlugin.ATTR_WORKING_DIRECTORY); 311 if(tmp != null) { 312 return tmp; 313 } 314 } 315 return wd; 316 } 317 318 @Override createControl(Composite parent)319 public void createControl(Composite parent) { 320 super.createControl(parent); 321 PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IDebugHelpContextIds.PROCESS_PROPERTY_PAGE); 322 } 323 } 324