Révision 2274
tmp/org.txm.rcp/src/main/java/org/txm/rcp/editors/TXMEditor.java (revision 2274) | ||
---|---|---|
89 | 89 |
import org.txm.utils.logger.Log; |
90 | 90 |
|
91 | 91 |
/** |
92 |
* Base TXM result <code>EditorPart</code> composed of
|
|
92 |
* Base TXM result <code>EditorPart</code> composed of |
|
93 | 93 |
* - a main toolbar at the top |
94 | 94 |
* - display area |
95 | 95 |
* - a bottom toolbar at the bottom of the editor |
... | ... | |
99 | 99 |
* |
100 | 100 |
*/ |
101 | 101 |
public abstract class TXMEditor<T extends TXMResult> extends EditorPart implements ITXMResultEditor<T> { |
102 |
|
|
102 |
|
|
103 | 103 |
/** |
104 | 104 |
* ID to use in plugin.xml to contribute to the top toolbar. |
105 | 105 |
*/ |
106 | 106 |
public final static String TOP_TOOLBAR_ID = "TXMEditorTopToolBar"; //$NON-NLS-1$ |
107 |
|
|
107 | 108 |
public final static String BOTTOM_TOOLBAR_ID = "TXMEditorBottomToolBar"; //$NON-NLS-1$ |
108 |
|
|
109 |
//FIXME: SJ: bad idea to use the ID as title, need to change the system |
|
109 |
|
|
110 |
// FIXME: SJ: bad idea to use the ID as title, need to change the system
|
|
110 | 111 |
public final static String COMPUTING_PARAMETERS_GROUP_ID = TXMUIMessages.parameters; |
111 |
|
|
112 |
|
|
112 | 113 |
/** |
113 | 114 |
* ID defined in plugin.xml for the compute button contribution. |
114 | 115 |
*/ |
115 | 116 |
public final static String TOP_TOOLBAR_COMPUTE_BUTTON_ID = "compute"; //$NON-NLS-1$ |
116 |
|
|
117 |
|
|
117 | 118 |
/** |
118 | 119 |
* The editor main tool bar, positioned at the top of the editor. |
119 | 120 |
*/ |
120 | 121 |
protected TXMEditorToolBar topToolBar; |
121 |
|
|
122 |
|
|
122 | 123 |
/** |
123 | 124 |
* The main panel containing the displayed result |
124 | 125 |
*/ |
125 | 126 |
private GLComposite resultArea; |
126 |
|
|
127 |
|
|
127 | 128 |
/** |
128 | 129 |
* The editor bottom tool bar, positioned at the bottom of the editor. |
129 | 130 |
*/ |
130 | 131 |
protected TXMEditorToolBar bottomToolBar; |
131 |
|
|
132 |
|
|
132 | 133 |
/** |
133 | 134 |
* The parameters groups are added to this composite. contains the sub widgets of the default Top toolbar |
134 | 135 |
*/ |
135 | 136 |
private GLComposite extendedParametersComposite; |
136 |
|
|
137 |
|
|
137 | 138 |
/** |
138 |
* Command main parameters that are always visible in the toolbar.
|
|
139 |
* Command main parameters that are always visible in the toolbar. |
|
139 | 140 |
*/ |
140 | 141 |
protected GLComposite mainParametersComposite; |
141 |
|
|
142 |
|
|
142 |
|
|
143 |
|
|
143 | 144 |
/** |
144 | 145 |
* Command extended parameters group that can be hidden. |
145 | 146 |
*/ |
146 | 147 |
protected Group extendedParametersGroup; |
147 |
|
|
148 |
|
|
148 | 149 |
/** |
149 | 150 |
* The SWT parent Composite. |
150 | 151 |
*/ |
151 | 152 |
protected Composite parent; |
152 |
|
|
153 |
|
|
153 | 154 |
/** |
154 | 155 |
* contains the default bottom toolbars widget |
155 | 156 |
*/ |
156 | 157 |
protected Composite bottomToolBarContainer; |
157 |
|
|
158 |
|
|
158 | 159 |
/** |
159 | 160 |
* Computing tool item button. |
160 | 161 |
*/ |
161 | 162 |
protected ToolItem computeButton; |
162 |
|
|
163 |
|
|
163 | 164 |
/** |
164 |
* To keep track of the parameters used for the last computing and updates only the widgets if a parameter has changed.
|
|
165 |
* To keep track of the parameters used for the last computing and updates only the widgets if a parameter has changed. |
|
165 | 166 |
*/ |
166 | 167 |
// FIXME: SJ: useless? |
167 |
//protected HashMap<String, Object> lastComputingParameters = new HashMap<String, Object>(); |
|
168 |
|
|
168 |
// protected HashMap<String, Object> lastComputingParameters = new HashMap<String, Object>();
|
|
169 |
|
|
169 | 170 |
/** |
170 | 171 |
* contains bottom toolbar subwidgets (installed grouped, etc.) |
171 | 172 |
*/ |
172 | 173 |
private GLComposite bottomSubWidgetsComposite; |
174 |
|
|
173 | 175 |
private GLComposite firstLineComposite; |
176 |
|
|
174 | 177 |
private boolean createPartControlDoneSucessfully = true; // FIXME: MD: for now... muahahaha |
175 |
|
|
178 |
|
|
176 | 179 |
/** |
177 | 180 |
* installed extensions |
178 | 181 |
*/ |
179 | 182 |
protected HashSet<TXMEditorExtension<T>> extensions = new HashSet<TXMEditorExtension<T>>(); |
180 |
|
|
181 |
|
|
183 |
|
|
184 |
|
|
182 | 185 |
/** |
183 | 186 |
* Linked editors. |
184 | 187 |
*/ |
185 | 188 |
protected ArrayList<EditorPart> linkedEditors = null; |
186 |
|
|
189 |
|
|
187 | 190 |
/** |
188 | 191 |
* debug purpose variable -> easier to fetch information that the getResult() method |
189 | 192 |
*/ |
190 | 193 |
protected T result; |
191 |
|
|
194 |
|
|
192 | 195 |
/** |
193 | 196 |
* To store or edit the dirty state of the editor from widget. |
194 | 197 |
*/ |
195 | 198 |
protected boolean dirty = true; |
199 |
|
|
196 | 200 |
private boolean locked = false; |
197 |
|
|
198 |
|
|
201 |
|
|
199 | 202 |
/** |
200 | 203 |
* Default constructor. |
201 | 204 |
*/ |
202 | 205 |
public TXMEditor() { |
206 |
|
|
203 | 207 |
super(); |
204 | 208 |
} |
205 |
|
|
209 |
|
|
206 | 210 |
/** |
207 | 211 |
* Creates an editor and an editor input containing the specified result. |
212 |
* |
|
208 | 213 |
* @param result |
209 | 214 |
*/ |
210 | 215 |
public TXMEditor(TXMResult result) { |
216 |
|
|
211 | 217 |
this(new TXMResultEditorInput<TXMResult>(result)); |
212 | 218 |
} |
213 |
|
|
214 |
|
|
219 |
|
|
215 | 220 |
/** |
216 | 221 |
* Creates an editor with the specified editor input. |
222 |
* |
|
217 | 223 |
* @param editorInput |
218 | 224 |
*/ |
219 | 225 |
public TXMEditor(TXMResultEditorInput<TXMResult> editorInput) { |
220 |
this.setInput(editorInput); // FIXME: SJ: the input is defined twice, on time here and one time in init(), need to see if we still need the assignment here in the constructor |
|
226 |
|
|
227 |
this.setInput(editorInput); // FIXME: SJ: the input is defined twice, on time here and one time in init(), need to see if we still need the assignment here in the constructor |
|
221 | 228 |
} |
222 |
|
|
223 |
|
|
229 |
|
|
224 | 230 |
@Override |
225 | 231 |
public void init(IEditorSite site, IEditorInput input) throws PartInitException { |
232 |
|
|
226 | 233 |
this.setSite(site); |
227 | 234 |
this.setInput(input); |
228 | 235 |
this.result = this.getEditorInput().getResult(); // store result for debug purpose |
229 |
// this.result.addResultListener(this);
|
|
236 |
// this.result.addResultListener(this);
|
|
230 | 237 |
// FIXME: see how to use the Adapters and AdapterFactory to define image and title of Editor in the contributing plug-ins |
231 |
// another way is to use editors extension in plug-ins and redefine icon and name, using this solution the problem is that the name (which is also editor title) can not be dynamic according to the result data |
|
238 |
// another way is to use editors extension in plug-ins and redefine icon and name, using this solution the problem is that the name (which is also editor title) can not be dynamic according to |
|
239 |
// the result data |
|
232 | 240 |
// so it seems better to use Adapters if it's possible or keep this solution below |
233 | 241 |
this.setPartName(input.getName()); |
234 |
|
|
242 |
|
|
235 | 243 |
// fetch extensions |
236 | 244 |
this.initExtensions(); |
237 | 245 |
} |
238 |
|
|
239 |
|
|
246 |
|
|
240 | 247 |
/** |
241 | 248 |
* Initializes plug-ins extensions. |
242 | 249 |
*/ |
243 |
public void initExtensions() {
|
|
244 |
|
|
250 |
public void initExtensions() {
|
|
251 |
|
|
245 | 252 |
IConfigurationElement[] config = Platform.getExtensionRegistry().getConfigurationElementsFor(TXMEditorExtension.EXTENSION_ID); |
246 | 253 |
if (config.length > 0) { |
247 |
|
|
254 |
|
|
248 | 255 |
for (IConfigurationElement e : config) { |
249 | 256 |
try { |
250 |
Log.finer(" "+e.getName()+" from "+e.getContributor().getName()); //$NON-NLS-1$ //$NON-NLS-2$
|
|
257 |
Log.finer(" " + e.getName() + " from " + e.getContributor().getName()); //$NON-NLS-1$ //$NON-NLS-2$
|
|
251 | 258 |
final Object o = e.createExecutableExtension("class"); //$NON-NLS-1$ |
252 | 259 |
if (o instanceof TXMEditorExtension) { |
253 | 260 |
ISafeRunnable runnable = new ISafeRunnable() { |
254 |
|
|
261 |
|
|
255 | 262 |
@Override |
256 | 263 |
public void handleException(Throwable exception) { |
257 |
Log.severe("Error while installing: "+o+": "+ exception.getLocalizedMessage()); //$NON-NLS-1$ //$NON-NLS-2$ |
|
264 |
|
|
265 |
Log.severe("Error while installing: " + o + ": " + exception.getLocalizedMessage()); //$NON-NLS-1$ //$NON-NLS-2$ |
|
258 | 266 |
} |
259 |
|
|
267 |
|
|
260 | 268 |
@Override |
261 | 269 |
public void run() throws Exception { |
270 |
|
|
262 | 271 |
@SuppressWarnings("unchecked") |
263 | 272 |
TXMEditorExtension<T> ext = ((TXMEditorExtension<T>) o); |
264 | 273 |
TXMResult r = getResult(); |
265 | 274 |
if (r == null) return; |
266 |
|
|
275 |
|
|
267 | 276 |
if (ext.getTXMResultValidClasses() == null || ext.getTXMResultValidClasses().contains(getResult().getClass())) { |
268 |
Log.finer("Installing TXMEditorExtension: "+ext.getName()); //$NON-NLS-1$
|
|
277 |
Log.finer("Installing TXMEditorExtension: " + ext.getName()); //$NON-NLS-1$
|
|
269 | 278 |
ext.setEditor(TXMEditor.this); |
270 | 279 |
extensions.add(ext); |
271 | 280 |
} |
... | ... | |
273 | 282 |
}; |
274 | 283 |
SafeRunner.run(runnable); |
275 | 284 |
} |
276 |
} catch (Exception ex) { |
|
285 |
} |
|
286 |
catch (Exception ex) { |
|
277 | 287 |
Log.severe("Exception while installing " + e.getName() + ": " + ex.getLocalizedMessage()); //$NON-NLS-1$ //$NON-NLS-2$ |
278 | 288 |
} |
279 | 289 |
} |
280 | 290 |
} |
281 |
|
|
291 |
|
|
282 | 292 |
IPartListener2 pl = new IPartListener2() { |
293 |
|
|
283 | 294 |
// ... Other methods |
284 | 295 |
public void partClosed(IWorkbenchPartReference partRef) { |
285 |
|
|
286 |
// if (getResult() != null) {
|
|
287 |
// getResult().removeResultListener(TXMEditor.this);
|
|
288 |
// }
|
|
289 |
|
|
296 |
|
|
297 |
// if (getResult() != null) {
|
|
298 |
// getResult().removeResultListener(TXMEditor.this);
|
|
299 |
// }
|
|
300 |
|
|
290 | 301 |
if (partRef.getId().equals(TXMEditor.this.getClass().getName())) { // called after this.doSave() |
291 |
|
|
292 |
//System.out.println("EVENT partClosed"); |
|
302 |
|
|
303 |
// System.out.println("EVENT partClosed");
|
|
293 | 304 |
for (TXMEditorExtension<T> extension : extensions) { |
294 | 305 |
try { |
295 | 306 |
if (extension.isDirty()) { |
296 | 307 |
extension.discardChanges(); |
297 | 308 |
} |
298 |
} catch (Exception e) { |
|
309 |
} |
|
310 |
catch (Exception e) { |
|
299 | 311 |
// TODO Auto-generated catch block |
300 | 312 |
e.printStackTrace(); |
301 | 313 |
} |
302 | 314 |
} |
303 | 315 |
} |
304 | 316 |
} |
305 |
|
|
317 |
|
|
306 | 318 |
@Override |
307 | 319 |
public void partActivated(IWorkbenchPartReference partRef) { |
308 |
// FIXME: SJ: why? when opening a new Editor the view will be refreshed twice... |
|
320 |
|
|
321 |
// FIXME: SJ: why? when opening a new Editor the view will be refreshed twice... |
|
309 | 322 |
CorporaView.refresh(); |
310 | 323 |
} |
311 |
|
|
324 |
|
|
312 | 325 |
@Override |
313 |
public void partBroughtToTop(IWorkbenchPartReference partRef) { }
|
|
314 |
|
|
326 |
public void partBroughtToTop(IWorkbenchPartReference partRef) {} |
|
327 |
|
|
315 | 328 |
@Override |
316 |
public void partDeactivated(IWorkbenchPartReference partRef) { }
|
|
317 |
|
|
329 |
public void partDeactivated(IWorkbenchPartReference partRef) {} |
|
330 |
|
|
318 | 331 |
@Override |
319 |
public void partOpened(IWorkbenchPartReference partRef) { }
|
|
320 |
|
|
332 |
public void partOpened(IWorkbenchPartReference partRef) {} |
|
333 |
|
|
321 | 334 |
@Override |
322 |
public void partHidden(IWorkbenchPartReference partRef) { }
|
|
323 |
|
|
335 |
public void partHidden(IWorkbenchPartReference partRef) {} |
|
336 |
|
|
324 | 337 |
@Override |
325 |
public void partVisible(IWorkbenchPartReference partRef) { }
|
|
326 |
|
|
338 |
public void partVisible(IWorkbenchPartReference partRef) {} |
|
339 |
|
|
327 | 340 |
@Override |
328 |
public void partInputChanged(IWorkbenchPartReference partRef) { }
|
|
329 |
|
|
341 |
public void partInputChanged(IWorkbenchPartReference partRef) {} |
|
342 |
|
|
330 | 343 |
}; |
331 | 344 |
this.getEditorSite().getPage().addPartListener(pl); |
332 | 345 |
} |
333 |
|
|
346 |
|
|
334 | 347 |
/** |
335 | 348 |
* the composite containing the main parameters, the top toolbar and eventually other top toolbars |
349 |
* |
|
336 | 350 |
* @return |
337 | 351 |
*/ |
338 | 352 |
public GLComposite getFirstLineComposite() { |
353 |
|
|
339 | 354 |
return firstLineComposite; |
340 | 355 |
} |
341 |
|
|
342 |
|
|
356 |
|
|
357 |
|
|
343 | 358 |
/** |
344 | 359 |
* Gets the shell of the parent composite if exists and not disposed otherwise the Display default active shell. |
360 |
* |
|
345 | 361 |
* @return |
346 | 362 |
*/ |
347 | 363 |
public Shell getShell() { |
348 |
if (parent !=null && !parent.isDisposed()) { |
|
349 |
return parent.getShell(); |
|
350 |
} |
|
364 |
|
|
365 |
if (parent != null && !parent.isDisposed()) { return parent.getShell(); } |
|
351 | 366 |
return Display.getDefault().getActiveShell(); |
352 | 367 |
} |
353 |
|
|
368 |
|
|
354 | 369 |
/** |
355 |
*
|
|
370 |
* |
|
356 | 371 |
* @return the composite displayed before the toptoolbar, containing the minimal parameters widgets |
357 | 372 |
*/ |
358 | 373 |
public GLComposite getMainParametersComposite() { |
374 |
|
|
359 | 375 |
return mainParametersComposite; |
360 | 376 |
} |
361 |
|
|
377 |
|
|
362 | 378 |
/** |
363 | 379 |
* Creates the default toolbar (empty) and default result area (empty). |
364 | 380 |
* |
365 | 381 |
*/ |
366 | 382 |
@Override |
367 | 383 |
public final void createPartControl(Composite parent) { |
368 |
|
|
384 |
|
|
369 | 385 |
try { |
370 | 386 |
this.parent = parent; |
371 |
|
|
387 |
|
|
372 | 388 |
// disable the rendering while creating the widgets |
373 | 389 |
// FIXME: SJ: would be very nice to do that to avoid to see the empty tables before the refresh() that fill the UI. |
374 | 390 |
// the re-enabling is done in refresh() but the EditionEditor doesn't seem to call refresh() so it breaks it |
375 |
//this.parent.setRedraw(false); |
|
376 |
|
|
391 |
// this.parent.setRedraw(false);
|
|
392 |
|
|
377 | 393 |
// to hide and display the extended parameters composite |
378 | 394 |
this.initParentLayout(parent, 1); |
379 |
|
|
395 |
|
|
380 | 396 |
// contains the minimal panels and top toolbars |
381 | 397 |
this.firstLineComposite = new GLComposite(parent, SWT.NONE, "Editor first line"); //$NON-NLS-1$ |
382 | 398 |
this.firstLineComposite.getLayout().numColumns = 2; |
383 | 399 |
this.firstLineComposite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false)); |
384 |
|
|
400 |
|
|
385 | 401 |
this.mainParametersComposite = new GLComposite(this.firstLineComposite, SWT.NONE, "Main parameters area"); //$NON-NLS-1$ |
386 | 402 |
this.mainParametersComposite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false)); |
387 | 403 |
this.mainParametersComposite.getLayout().marginLeft = 5; |
388 | 404 |
this.mainParametersComposite.getLayout().horizontalSpacing = 5; |
389 |
|
|
405 |
|
|
390 | 406 |
this.extendedParametersComposite = new GLComposite(parent, SWT.NONE, "Extended parameters area"); //$NON-NLS-1$ |
391 | 407 |
this.extendedParametersComposite.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); |
392 |
|
|
408 |
|
|
393 | 409 |
this.topToolBar = new TXMEditorToolBar(this, this.firstLineComposite, this.extendedParametersComposite, SWT.FLAT | SWT.RIGHT, TOP_TOOLBAR_ID); |
394 |
|
|
410 |
|
|
395 | 411 |
// store the Compute button to access if later, especially from subclasses |
396 | 412 |
this.computeButton = topToolBar.getItemByContributionId(TOP_TOOLBAR_COMPUTE_BUTTON_ID); |
397 | 413 |
|
398 |
// this.computeButton = new ToolItem(topToolBar, SWT.PUSH);//.topToolBar.getItemByContributionId(TOP_TOOLBAR_COMPUTE_BUTTON_ID);
|
|
399 |
// this.computeButton.setImage(IImageKeys.getImage(IImageKeys.START));
|
|
400 |
// this.computeButton.addSelectionListener(new ComputeSelectionListener(this, true));
|
|
414 |
// this.computeButton = new ToolItem(topToolBar, SWT.PUSH);//.topToolBar.getItemByContributionId(TOP_TOOLBAR_COMPUTE_BUTTON_ID);
|
|
415 |
// this.computeButton.setImage(IImageKeys.getImage(IImageKeys.START));
|
|
416 |
// this.computeButton.addSelectionListener(new ComputeSelectionListener(this, true));
|
|
401 | 417 |
|
402 | 418 |
// computing parameters components |
403 | 419 |
boolean showExtendedParameters = false; |
404 | 420 |
// only show the area if the result can not compute and is dirty |
405 |
// FIXME: to discuss about when hiding or showing the extended parameters
|
|
406 |
// if(!this.getResult().canCompute() && this.getResult().isDirty()) {
|
|
407 |
// showExtendedParameters = true;
|
|
408 |
// }
|
|
409 |
this.extendedParametersGroup = this.topToolBar.installGroup(COMPUTING_PARAMETERS_GROUP_ID, TXMUIMessages.showHideCommandParameters,
|
|
421 |
// FIXME: to discuss about when hiding or showing the extended parameters |
|
422 |
// if(!this.getResult().canCompute() && this.getResult().isDirty()) {
|
|
423 |
// showExtendedParameters = true;
|
|
424 |
// }
|
|
425 |
this.extendedParametersGroup = this.topToolBar.installGroup(COMPUTING_PARAMETERS_GROUP_ID, TXMUIMessages.showHideCommandParameters, |
|
410 | 426 |
"icons/show_computing_parameters.png", //$NON-NLS-1$ |
411 | 427 |
"icons/hide_computing_parameters.png", //$NON-NLS-1$ |
412 | 428 |
showExtendedParameters); |
413 |
|
|
429 |
|
|
414 | 430 |
// display main area |
415 | 431 |
this.resultArea = new GLComposite(parent, SWT.NONE, "Result area"); //$NON-NLS-1$ |
416 | 432 |
this.resultArea.setLayoutData(new GridData(GridData.FILL_BOTH)); |
417 |
|
|
433 |
|
|
418 | 434 |
// create the bottom tool bar |
419 | 435 |
this.bottomToolBarContainer = new Composite(parent, SWT.NONE); |
420 | 436 |
this.bottomToolBarContainer.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false)); |
421 | 437 |
RowLayout rl = new RowLayout(SWT.HORIZONTAL); |
422 | 438 |
rl.marginTop = rl.marginHeight = rl.marginWidth = rl.marginBottom = 0; |
423 |
//rl.center = true; |
|
424 |
//rl.justify = true; |
|
439 |
// rl.center = true;
|
|
440 |
// rl.justify = true;
|
|
425 | 441 |
this.bottomToolBarContainer.setLayout(rl); |
426 |
|
|
442 |
|
|
427 | 443 |
this.bottomSubWidgetsComposite = new GLComposite(parent, SWT.NONE, "Bottom parameters area"); //$NON-NLS-1$ |
428 |
if (parent.getLayout() instanceof GridLayout) {
|
|
444 |
if (parent.getLayout() instanceof GridLayout) {
|
|
429 | 445 |
this.bottomSubWidgetsComposite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false)); |
430 | 446 |
} |
431 |
|
|
447 |
|
|
432 | 448 |
this.bottomToolBar = new TXMEditorToolBar(this, this.bottomToolBarContainer, this.bottomSubWidgetsComposite, SWT.FLAT, "bottom"); //$NON-NLS-1$ |
433 |
|
|
449 |
|
|
434 | 450 |
this.notifyExtensions("notifyStartOfCreatePartControl"); //$NON-NLS-1$ |
435 | 451 |
this._createPartControl(); // child editor creates its parameters and displays widgets |
436 | 452 |
this.notifyExtensions("notifyEndOfCreatePartControl"); //$NON-NLS-1$ |
437 |
|
|
453 |
|
|
438 | 454 |
this.firstLineComposite.pack(); |
439 | 455 |
this.extendedParametersGroup.pack(); |
440 |
|
|
441 |
|
|
456 |
|
|
457 |
|
|
442 | 458 |
// remove empty toolbar |
443 |
//TODO SJ: Hack? MD: yeah -> need to find a way to not display the bottom toolbar on Windows instead |
|
459 |
// TODO SJ: Hack? MD: yeah -> need to find a way to not display the bottom toolbar on Windows instead
|
|
444 | 460 |
if (this.bottomToolBar.getItems().length == 0) { |
445 | 461 |
this.bottomToolBar.dispose(); |
446 | 462 |
} |
447 |
|
|
463 |
|
|
448 | 464 |
// remove empty toolbar |
449 |
//TODO SJ: Hack? MD: yeah -> need to find a way to not display the bottom toolbar on Windows instead |
|
465 |
// TODO SJ: Hack? MD: yeah -> need to find a way to not display the bottom toolbar on Windows instead
|
|
450 | 466 |
if (this.topToolBar.getItems().length == 0) { |
451 | 467 |
this.topToolBar.dispose(); |
452 | 468 |
} |
453 |
|
|
469 |
|
|
454 | 470 |
// uninstall parameters group if not used |
455 | 471 |
if (this.extendedParametersGroup.getChildren().length == 0) { |
456 | 472 |
this.topToolBar.unInstallGroup(COMPUTING_PARAMETERS_GROUP_ID); |
457 | 473 |
} |
458 |
|
|
474 |
|
|
459 | 475 |
// FIXME: SJ: this code doesn't work even if we call removeComputeButton() |
460 | 476 |
// remove empty first line composite |
461 |
// if(this.mainParametersComposite.getChildren().length == 0 && this.topToolBar.isDisposed()) {
|
|
462 |
// this.firstLineComposite.dispose();
|
|
463 |
// }
|
|
464 |
|
|
465 |
|
|
477 |
// if(this.mainParametersComposite.getChildren().length == 0 && this.topToolBar.isDisposed()) {
|
|
478 |
// this.firstLineComposite.dispose();
|
|
479 |
// }
|
|
480 |
|
|
481 |
|
|
466 | 482 |
if (this.getResult() != null && this.getResult().isLocked()) { |
467 | 483 |
this.setLocked(true); |
468 | 484 |
} |
469 |
|
|
485 |
|
|
470 | 486 |
// disable the compute button, it will be re-enable or not later when the UI will check if the editor is dirty or not |
471 |
// ToolItem computeButton = this.topToolBar.getItemByContributionId(TOP_TOOLBAR_COMPUTE_BUTTON_ID); |
|
472 |
// if (computeButton != null) { |
|
473 |
// computeButton.setEnabled(false); |
|
474 |
// } |
|
475 |
|
|
487 |
// ToolItem computeButton = this.topToolBar.getItemByContributionId(TOP_TOOLBAR_COMPUTE_BUTTON_ID); |
|
488 |
// if (computeButton != null) { |
|
489 |
// computeButton.setEnabled(false); |
|
490 |
// } |
|
476 | 491 |
|
492 |
|
|
477 | 493 |
// dirty state according to the future compute that will be launched by TXMEditor.openEditor() |
478 |
if(this.getResult().canCompute()) {
|
|
494 |
if (this.getResult().canCompute()) {
|
|
479 | 495 |
this.dirty = false; |
480 | 496 |
} |
481 |
|
|
497 |
|
|
482 | 498 |
this.setDirty(this.dirty); |
483 |
|
|
484 |
//this.parent.setRedraw(true); |
|
485 |
|
|
486 | 499 |
|
500 |
// this.parent.setRedraw(true); |
|
501 |
|
|
502 |
|
|
487 | 503 |
} |
488 |
catch(Throwable e) { |
|
504 |
catch (Throwable e) {
|
|
489 | 505 |
Log.severe(TXMCoreMessages.bind("TXMEditor.createPartControl(): can not create the editor for result {0}.", this.getResult())); //$NON-NLS-1$ |
490 | 506 |
e.printStackTrace(); |
491 | 507 |
createPartControlDoneSucessfully = false; |
492 | 508 |
} |
493 |
|
|
509 |
|
|
494 | 510 |
} |
495 |
|
|
511 |
|
|
496 | 512 |
public void setLocked(boolean b) { |
513 |
|
|
497 | 514 |
this.locked = b; |
498 | 515 |
this.firstLineComposite.setEnabled(!b); |
499 | 516 |
} |
500 |
|
|
517 |
|
|
501 | 518 |
public boolean isLocked() { |
519 |
|
|
502 | 520 |
return locked; |
503 | 521 |
} |
504 |
|
|
522 |
|
|
505 | 523 |
/** |
506 | 524 |
* shortcut to call the notify* methods of all extension |
507 | 525 |
* |
... | ... | |
522 | 540 |
* @throws NoSuchMethodException |
523 | 541 |
*/ |
524 | 542 |
protected void notifyExtensions(final String step) { |
543 |
|
|
525 | 544 |
if (!step.startsWith("notify")) return; //$NON-NLS-1$ |
526 |
|
|
545 |
|
|
527 | 546 |
ArrayList<TXMEditorExtension<T>> errors = new ArrayList<TXMEditorExtension<T>>(); |
528 | 547 |
for (final TXMEditorExtension<T> ext : extensions) { |
529 |
// ISafeRunnable runnable = new ISafeRunnable() {
|
|
530 |
// @Override
|
|
531 |
// public void handleException(Throwable exception) {
|
|
532 |
// System.out.println("Error while installing: "+ext+": "+ exception.getLocalizedMessage());
|
|
533 |
// }
|
|
548 |
// ISafeRunnable runnable = new ISafeRunnable() {
|
|
549 |
// @Override
|
|
550 |
// public void handleException(Throwable exception) {
|
|
551 |
// System.out.println("Error while installing: "+ext+": "+ exception.getLocalizedMessage());
|
|
552 |
// }
|
|
534 | 553 |
// |
535 |
// @Override
|
|
536 |
// public void run() throws Exception {
|
|
554 |
// @Override
|
|
555 |
// public void run() throws Exception {
|
|
537 | 556 |
try { |
538 | 557 |
java.lang.reflect.Method method; |
539 | 558 |
method = ext.getClass().getMethod(step); |
540 | 559 |
if (method != null) { |
541 | 560 |
method.invoke(ext); |
542 |
} else { |
|
561 |
} |
|
562 |
else { |
|
543 | 563 |
ext.notify(step); |
544 | 564 |
} |
545 |
} catch(Throwable e) { |
|
546 |
//errors.add(ext); |
|
547 |
Log.warning("Can't notify of "+step+" the \"+ext+\" extension: "+e); |
|
565 |
} |
|
566 |
catch (Throwable e) { |
|
567 |
// errors.add(ext); |
|
568 |
Log.warning("Can't notify of " + step + " the \"+ext+\" extension: " + e); |
|
548 | 569 |
Log.printStackTrace(e); |
549 | 570 |
} |
550 |
// }
|
|
551 |
// };
|
|
552 |
// SafeRunner.run(runnable);
|
|
571 |
// }
|
|
572 |
// };
|
|
573 |
// SafeRunner.run(runnable);
|
|
553 | 574 |
} |
554 | 575 |
extensions.removeAll(errors); |
555 | 576 |
} |
556 |
|
|
577 |
|
|
557 | 578 |
/** |
558 | 579 |
* Subclasses manual creation method called after TXMEditor.createPartControl is called. |
559 | 580 |
* |
560 | 581 |
* Use this method to set your own widgets in the minimal parameters area, the top toolbar, parameters group, the result area and the bottom toolbar |
561 |
* @throws Exception |
|
582 |
* |
|
583 |
* @throws Exception |
|
562 | 584 |
*/ |
563 | 585 |
public abstract void _createPartControl() throws Exception; |
564 |
|
|
586 |
|
|
565 | 587 |
/** |
566 | 588 |
* Use this method to add widget next to the default Bottom toolbar |
567 | 589 |
* |
568 |
* @return the composite that contains the default Bottom toolbar.
|
|
590 |
* @return the composite that contains the default Bottom toolbar. |
|
569 | 591 |
*/ |
570 | 592 |
public Composite getBottomToolBarContainer() { |
593 |
|
|
571 | 594 |
return bottomToolBarContainer; |
572 | 595 |
} |
573 |
|
|
596 |
|
|
574 | 597 |
/** |
575 | 598 |
* Gets the top toolbar. |
599 |
* |
|
576 | 600 |
* @return the default Top toolbar of TXMEditors |
577 | 601 |
*/ |
578 | 602 |
public TXMEditorToolBar getTopToolbar() { |
603 |
|
|
579 | 604 |
return topToolBar; |
580 | 605 |
} |
581 |
|
|
606 |
|
|
582 | 607 |
/** |
583 | 608 |
* Gets the result display area. |
584 | 609 |
* The user must configure its layout. |
610 |
* |
|
585 | 611 |
* @return |
586 | 612 |
*/ |
587 | 613 |
public GLComposite getResultArea() { |
614 |
|
|
588 | 615 |
return resultArea; |
589 | 616 |
} |
590 |
|
|
617 |
|
|
591 | 618 |
/** |
592 | 619 |
* Gets the bottom toolbar. |
620 |
* |
|
593 | 621 |
* @return the default bottom toolbar of editors |
594 | 622 |
*/ |
595 | 623 |
public TXMEditorToolBar getBottomToolbar() { |
624 |
|
|
596 | 625 |
return bottomToolBar; |
597 | 626 |
} |
598 |
|
|
627 |
|
|
599 | 628 |
/** |
600 | 629 |
* Creates the parent layout with some configuration to make children composite visible/invisible. |
601 | 630 |
* |
602 | 631 |
* @param colSpan |
603 | 632 |
*/ |
604 |
public void initParentLayout(Composite parent, int colSpan) { |
|
633 |
public void initParentLayout(Composite parent, int colSpan) { |
|
634 |
|
|
605 | 635 |
GridLayout gl = GLComposite.createDefaultLayout(1); |
606 | 636 |
parent.setLayout(gl); |
607 | 637 |
} |
608 |
|
|
638 |
|
|
609 | 639 |
/** |
610 | 640 |
* Gets the extended parameters Group widget. |
611 | 641 |
* Put here you main parameter widgets using RowData data layout. |
612 | 642 |
* |
613 |
* @return the extendedParametersGroup
|
|
643 |
* @return the extendedParametersGroup |
|
614 | 644 |
*/ |
615 | 645 |
public Group getExtendedParametersGroup() { |
646 |
|
|
616 | 647 |
return this.extendedParametersGroup; |
617 | 648 |
} |
618 |
|
|
619 |
|
|
649 |
|
|
650 |
|
|
620 | 651 |
@Override |
621 | 652 |
public boolean isSaveAsAllowed() { |
653 |
|
|
622 | 654 |
// TODO Auto-generated method stub |
623 | 655 |
return false; |
624 | 656 |
} |
625 |
|
|
657 |
|
|
626 | 658 |
@Override |
627 | 659 |
public void doSave(final IProgressMonitor monitor) { |
628 | 660 |
// FIXME: SJ: to discuss. A this moment the save is automatically done or not in TXMResult.compute() according to a preference of the TBX |
629 |
// if (TBXPreferences.getInstance().getBoolean(TBXPreferences.AUTO_SAVE_RESULTS)) { // ?
|
|
630 |
// getResult().saveParameters();
|
|
631 |
// }
|
|
632 |
|
|
661 |
// if (TBXPreferences.getInstance().getBoolean(TBXPreferences.AUTO_SAVE_RESULTS)) { // ?
|
|
662 |
// getResult().saveParameters();
|
|
663 |
// }
|
|
664 |
|
|
633 | 665 |
/// FIXME: SJ: dirty state tests |
634 | 666 |
if (parent != null && !parent.isDisposed()) { |
635 | 667 |
parent.getDisplay().asyncExec(new Runnable() { |
636 |
|
|
668 |
|
|
637 | 669 |
@Override |
638 | 670 |
public void run() { |
671 |
|
|
639 | 672 |
compute(true); |
640 | 673 |
TXMEditor.this.setDirty(false); |
641 | 674 |
} |
642 | 675 |
}); |
643 | 676 |
} |
644 |
|
|
677 |
|
|
645 | 678 |
notifyExtensions("notifyDoSave"); //$NON-NLS-1$ |
646 | 679 |
firePropertyChange(IEditorPart.PROP_DIRTY); |
647 | 680 |
} |
648 |
|
|
681 |
|
|
649 | 682 |
@Override |
650 | 683 |
public void doSaveAs() { |
651 | 684 |
// TODO Auto-generated method stub |
652 | 685 |
} |
653 |
|
|
686 |
|
|
654 | 687 |
@Override |
655 | 688 |
public void dispose() { |
689 |
|
|
656 | 690 |
notifyExtensions("notifyDispose"); //$NON-NLS-1$ |
657 | 691 |
super.dispose(); |
658 | 692 |
} |
659 |
|
|
693 |
|
|
660 | 694 |
/** |
661 | 695 |
* Sets the dirty state of the editor. |
662 | 696 |
* Also sets the result dirty state to true if editor is dirty. |
... | ... | |
665 | 699 |
* @param dirty |
666 | 700 |
*/ |
667 | 701 |
public void setDirty(boolean dirty) { |
702 |
|
|
668 | 703 |
this.dirty = dirty; |
669 |
|
|
704 |
|
|
670 | 705 |
// FIXME: SJ: future version that enable the button ONLY if the result can compute |
671 | 706 |
// need to check all canCompute() result methods before enabling it |
672 |
// try {
|
|
673 |
// // enable/disable the compute button according to dirty state of the editor
|
|
674 |
// if (this.computeButton != null && !this.computeButton.isDisposed()) {
|
|
675 |
// this.computeButton.setEnabled(this.getResult().canCompute() && dirty && !this.getResult().isLocked());
|
|
676 |
// }
|
|
677 |
// }
|
|
678 |
// catch (Exception e) {
|
|
679 |
// // TODO Auto-generated catch block
|
|
680 |
// e.printStackTrace();
|
|
681 |
// }
|
|
682 |
|
|
683 |
// // FIXME: sometime the button is enable/disable when it should not
|
|
684 |
// // enable/disable the compute button according to dirty state of the editor
|
|
685 |
// if (this.computeButton != null && !this.computeButton.isDisposed()) {
|
|
686 |
// this.computeButton.setEnabled(this.dirty && !this.getResult().isLocked());
|
|
687 |
// }
|
|
688 |
|
|
707 |
// try {
|
|
708 |
// // enable/disable the compute button according to dirty state of the editor
|
|
709 |
// if (this.computeButton != null && !this.computeButton.isDisposed()) {
|
|
710 |
// this.computeButton.setEnabled(this.getResult().canCompute() && dirty && !this.getResult().isLocked());
|
|
711 |
// }
|
|
712 |
// }
|
|
713 |
// catch (Exception e) {
|
|
714 |
// // TODO Auto-generated catch block
|
|
715 |
// e.printStackTrace();
|
|
716 |
// }
|
|
717 |
|
|
718 |
// // FIXME: sometime the button is enable/disable when it should not
|
|
719 |
// // enable/disable the compute button according to dirty state of the editor
|
|
720 |
// if (this.computeButton != null && !this.computeButton.isDisposed()) {
|
|
721 |
// this.computeButton.setEnabled(this.dirty && !this.getResult().isLocked());
|
|
722 |
// }
|
|
723 |
|
|
689 | 724 |
firePropertyChange(IEditorPart.PROP_DIRTY); |
690 | 725 |
CorporaView.refreshObject(this.result); |
691 | 726 |
} |
692 |
|
|
727 |
|
|
693 | 728 |
@Override |
694 | 729 |
public boolean isDirty() { |
695 |
|
|
730 |
|
|
696 | 731 |
boolean dirty = this.dirty; |
697 |
|
|
732 |
|
|
698 | 733 |
for (TXMEditorExtension<T> extension : this.extensions) { |
699 | 734 |
try { |
700 | 735 |
dirty = dirty || extension.isDirty(); |
701 |
} catch (Exception e) { |
|
736 |
} |
|
737 |
catch (Exception e) { |
|
702 | 738 |
e.printStackTrace(); |
703 | 739 |
} |
704 | 740 |
} |
705 | 741 |
return dirty; |
706 | 742 |
} |
707 |
|
|
743 |
|
|
708 | 744 |
@Override |
709 | 745 |
public boolean isSaveOnCloseNeeded() { |
746 |
|
|
710 | 747 |
boolean needed = false; |
711 |
|
|
748 |
|
|
712 | 749 |
for (TXMEditorExtension<T> extension : this.extensions) { |
713 | 750 |
try { |
714 | 751 |
needed = needed || (extension.isSaveOnCloseNeeded() && extension.isDirty()); |
715 |
} catch (Exception e) { |
|
752 |
} |
|
753 |
catch (Exception e) { |
|
716 | 754 |
e.printStackTrace(); |
717 | 755 |
} |
718 | 756 |
} |
719 | 757 |
return needed; |
720 |
|
|
758 |
|
|
721 | 759 |
} |
722 |
|
|
723 |
|
|
724 |
|
|
760 |
|
|
725 | 761 |
@Override |
726 | 762 |
public void setFocus() { |
727 |
// this.resultArea.setFocus(); |
|
763 |
|
|
764 |
// this.resultArea.setFocus(); |
|
728 | 765 |
// FIXME SJ: this code leads to a bug, the focus must not be regiven to the main parameter after each computing of all result editors |
729 |
// if (mainParametersComposite != null && !mainParametersComposite.isDisposed()) {
|
|
730 |
// mainParametersComposite.setFocus();
|
|
731 |
// }
|
|
766 |
// if (mainParametersComposite != null && !mainParametersComposite.isDisposed()) {
|
|
767 |
// mainParametersComposite.setFocus();
|
|
768 |
// }
|
|
732 | 769 |
CorporaView.focus(this.getResult()); |
733 | 770 |
} |
734 |
|
|
735 |
|
|
771 |
|
|
736 | 772 |
@SuppressWarnings("unchecked") |
737 | 773 |
@Override |
738 | 774 |
public TXMResultEditorInput<T> getEditorInput() { |
775 |
|
|
739 | 776 |
return (TXMResultEditorInput<T>) super.getEditorInput(); |
740 | 777 |
} |
741 |
|
|
778 |
|
|
742 | 779 |
/** |
743 | 780 |
* Returns the result object associated with the editor through its editor input. |
781 |
* |
|
744 | 782 |
* @return |
745 | 783 |
*/ |
746 |
public T getResult() { |
|
784 |
public T getResult() { |
|
785 |
|
|
747 | 786 |
return this.getEditorInput().getResult(); |
748 | 787 |
} |
749 |
|
|
788 |
|
|
750 | 789 |
/** |
751 | 790 |
* Gets the value of the specified key in parameters, local result node or default preferences nodes. |
791 |
* |
|
752 | 792 |
* @param key |
753 | 793 |
* @return |
754 | 794 |
*/ |
755 |
public int getIntParameterValue(String key) { |
|
795 |
public int getIntParameterValue(String key) { |
|
796 |
|
|
756 | 797 |
return this.getEditorInput().getResult().getIntParameterValue(key); |
757 | 798 |
} |
758 |
|
|
799 |
|
|
759 | 800 |
/** |
760 | 801 |
* Gets the value of the specified key in parameters, local result node or default preferences nodes. |
802 |
* |
|
761 | 803 |
* @param key |
762 | 804 |
* @return |
763 | 805 |
*/ |
764 |
public float getFloatParameterValue(String key) { |
|
806 |
public float getFloatParameterValue(String key) { |
|
807 |
|
|
765 | 808 |
return this.getEditorInput().getResult().getFloatParameterValue(key); |
766 | 809 |
} |
767 |
|
|
810 |
|
|
768 | 811 |
/** |
769 | 812 |
* Gets the value of the specified key in parameters, local result node or default preferences nodes. |
813 |
* |
|
770 | 814 |
* @param key |
771 | 815 |
* @return |
772 | 816 |
*/ |
773 |
public double getDoubleParameterValue(String key) { |
|
817 |
public double getDoubleParameterValue(String key) { |
|
818 |
|
|
774 | 819 |
return this.getEditorInput().getResult().getDoubleParameterValue(key); |
775 | 820 |
} |
776 |
|
|
777 |
|
|
821 |
|
|
778 | 822 |
/** |
779 | 823 |
* Gets the value of the specified key in parameters, local result node or default preferences nodes. |
824 |
* |
|
780 | 825 |
* @param key |
781 | 826 |
* @return |
782 | 827 |
*/ |
783 |
public boolean getBooleanParameterValue(String key) { |
|
828 |
public boolean getBooleanParameterValue(String key) { |
|
829 |
|
|
784 | 830 |
return this.getEditorInput().getResult().getBooleanParameterValue(key); |
785 | 831 |
} |
786 |
|
|
832 |
|
|
787 | 833 |
/** |
788 | 834 |
* Gets the value of the specified key in parameters, local result node or default preferences nodes. |
835 |
* |
|
789 | 836 |
* @param key |
790 | 837 |
* @return |
791 | 838 |
*/ |
792 |
public long getLongParameterValue(String key) { |
|
839 |
public long getLongParameterValue(String key) { |
|
840 |
|
|
793 | 841 |
return this.getEditorInput().getResult().getLongParameterValue(key); |
794 | 842 |
} |
795 |
|
|
843 |
|
|
796 | 844 |
/** |
797 | 845 |
* Gets the value of the specified key in parameters, local result node or default preferences nodes. |
846 |
* |
|
798 | 847 |
* @param key |
799 | 848 |
* @return |
800 | 849 |
*/ |
801 |
public String getStringParameterValue(String key) { |
|
850 |
public String getStringParameterValue(String key) { |
|
851 |
|
|
802 | 852 |
return this.getEditorInput().getResult().getStringParameterValue(key); |
803 | 853 |
} |
804 |
|
|
805 | 854 |
|
806 | 855 |
// FIXME: SJ: tests to enable/disable when computing |
807 |
// public void recursiveSetEnabled(boolean enabled) {
|
|
808 |
// this.recursiveSetEnabled(this.parent, enabled);
|
|
809 |
// }
|
|
856 |
// public void recursiveSetEnabled(boolean enabled) {
|
|
857 |
// this.recursiveSetEnabled(this.parent, enabled);
|
|
858 |
// }
|
|
810 | 859 |
|
811 | 860 |
// FIXME: SJ: tests to enable/disable when computing |
812 |
// public void recursiveSetEnabled(Control ctrl, boolean enabled) {
|
|
813 |
// if (ctrl instanceof Composite) {
|
|
814 |
// Composite comp = (Composite) ctrl;
|
|
815 |
// for (Control c : comp.getChildren())
|
|
816 |
// recursiveSetEnabled(c, enabled);
|
|
817 |
// } else {
|
|
818 |
// ctrl.setEnabled(enabled);
|
|
819 |
// }
|
|
820 |
// }
|
|
861 |
// public void recursiveSetEnabled(Control ctrl, boolean enabled) {
|
|
862 |
// if (ctrl instanceof Composite) {
|
|
863 |
// Composite comp = (Composite) ctrl;
|
|
864 |
// for (Control c : comp.getChildren())
|
|
865 |
// recursiveSetEnabled(c, enabled);
|
|
866 |
// } else {
|
|
867 |
// ctrl.setEnabled(enabled);
|
|
868 |
// }
|
|
869 |
// }
|
|
821 | 870 |
|
822 | 871 |
/** |
823 | 872 |
* Computes the TXMResult if all required parameters are set then refreshes the editor UI. |
... | ... | |
826 | 875 |
* @param result |
827 | 876 |
* @param update force the editor to update its result parameters |
828 | 877 |
*/ |
829 |
public JobHandler compute(final boolean update) {
|
|
830 |
|
|
878 |
public JobHandler compute(final boolean update) {
|
|
879 |
|
|
831 | 880 |
StatusLine.setMessage(TXMCoreMessages.bind(TXMUIMessages.computing, this.getResult().getName())); |
832 |
|
|
881 |
|
|
833 | 882 |
JobHandler job = new JobHandler(TXMCoreMessages.bind(TXMUIMessages.computing, this.getResult().getName())) { |
834 |
|
|
883 |
|
|
835 | 884 |
@Override |
836 | 885 |
protected IStatus run(IProgressMonitor monitor) { |
837 |
|
|
886 |
|
|
838 | 887 |
this.runInit(monitor); |
839 |
|
|
840 |
if (isLocked()) { |
|
841 |
return Status.CANCEL_STATUS; |
|
842 |
} |
|
843 |
|
|
888 |
|
|
889 |
if (isLocked()) { return Status.CANCEL_STATUS; } |
|
890 |
|
|
844 | 891 |
try { |
845 | 892 |
JobsTimer.start(); |
846 |
|
|
893 |
|
|
847 | 894 |
// FIXME: SJ: tests |
848 |
//showBusy(true); |
|
849 |
|
|
895 |
// showBusy(true);
|
|
896 |
|
|
850 | 897 |
this.syncExec(new Runnable() { |
898 |
|
|
851 | 899 |
@Override |
852 | 900 |
public void run() { |
853 |
|
|
901 |
|
|
854 | 902 |
// FIXME: SJ: tests to enable/disable the editor widgets when computing |
855 |
//recursiveSetEnabled(false); |
|
903 |
// recursiveSetEnabled(false);
|
|
856 | 904 |
|
857 |
if(update) {
|
|
858 |
|
|
905 |
if (update) {
|
|
906 |
|
|
859 | 907 |
// popup alert to inform user that the result has been manually edited |
860 | 908 |
if (TXMEditor.this.getResult().isAltered() |
861 |
&& !MessageDialog.openQuestion(getShell(), TXMCoreMessages.common_warning, TXMCoreMessages.bind(TXMUIMessages.warning_popup_theP0HasBeenEditedItsChangesWillBeLost, TXMEditor.this.getResult().getResultType()))) { |
|
909 |
&& !MessageDialog.openQuestion(getShell(), TXMCoreMessages.common_warning, TXMCoreMessages.bind( |
|
910 |
TXMUIMessages.warning_popup_theP0HasBeenEditedItsChangesWillBeLost, TXMEditor.this.getResult().getResultType()))) { |
|
862 | 911 |
setCanceled(true); |
863 | 912 |
} |
864 | 913 |
// popup alert to inform user that children results will be recomputed |
865 |
if(!TBXPreferences.getInstance().getBoolean(TBXPreferences.EXPERT_USER) |
|
866 |
&& TXMEditor.this.getResult().hasVisibleChild() && !MessageDialog.openQuestion(getShell(), TXMCoreMessages.common_warning, TXMUIMessages.warning_popup_allDescendantResultsWillBeUpdated)) { |
|
914 |
if (!TBXPreferences.getInstance().getBoolean(TBXPreferences.EXPERT_USER) |
|
915 |
&& TXMEditor.this.getResult().hasVisibleChild() && !MessageDialog.openQuestion(getShell(), TXMCoreMessages.common_warning, |
|
916 |
TXMUIMessages.warning_popup_allDescendantResultsWillBeUpdated)) { |
|
867 | 917 |
setCanceled(true); |
868 | 918 |
} |
869 |
|
|
870 |
|
|
871 |
|
|
919 |
|
|
920 |
|
|
921 |
|
|
872 | 922 |
// subclasses manual result updating from editor fields |
873 | 923 |
Log.finer("TXMEditor.compute(): " + TXMEditor.this.getClass().getSimpleName() + ": manually updating result from editor."); //$NON-NLS-1$ |
874 | 924 |
updateResultFromEditor(); |
875 |
|
|
925 |
|
|
876 | 926 |
// auto updating result parameters from parameter annotations of editor |
877 | 927 |
Log.finer("TXMEditor.compute(): " + TXMEditor.this.getClass().getSimpleName() + ": auto updating result from editor."); //$NON-NLS-1$ |
878 | 928 |
autoUpdateResultFromEditorParameters(); |
879 |
|
|
880 |
|
|
881 |
|
|
929 |
|
|
930 |
|
|
931 |
|
|
882 | 932 |
// FIXME: SJ: useless at this time? |
883 |
// Stores the last parameters before the computing to later auto-update the Widgets only if some parameters have changed
|
|
884 |
//setLastComputingParameters(TXMEditor.this.getResult().getLastParametersFromHistory()); |
|
933 |
// Stores the last parameters before the computing to later auto-update the Widgets only if some parameters have changed |
|
934 |
// setLastComputingParameters(TXMEditor.this.getResult().getLastParametersFromHistory());
|
|
885 | 935 |
} |
886 | 936 |
// FIXME: SJ: there is a bug when deleting LT lines for example, the popup alert to inform user that children results will be recomputed is not triggered |
887 |
// problem here is the DeleteLines commands, etc. call TXMEditor.compute(false) at this moment, they should call TXMEditor.compute(true) but the LT Editor is not ready to manage that |
|
888 |
// else if(TXMEditor.this.getResult().hasBeenComputedOnce()) { |
|
889 |
// // popup alert to inform user that children results will be recomputed |
|
890 |
// if(!TBXPreferences.getInstance().getBoolean(TBXPreferences.EXPERT_USER) |
|
891 |
// && TXMEditor.this.getResult().hasVisibleChild() && !MessageDialog.openQuestion(getShell(), TXMCoreMessages.common_warning, TXMUIMessages.warning_popup_allDescendantResultsWillBeUpdated)) { |
|
892 |
// setCanceled(true); |
|
893 |
// } |
|
937 |
// problem here is the DeleteLines commands, etc. call TXMEditor.compute(false) at this moment, they should call TXMEditor.compute(true) but the LT Editor is not ready to |
|
938 |
// manage that |
|
939 |
// else if(TXMEditor.this.getResult().hasBeenComputedOnce()) { |
|
940 |
// // popup alert to inform user that children results will be recomputed |
|
941 |
// if(!TBXPreferences.getInstance().getBoolean(TBXPreferences.EXPERT_USER) |
|
942 |
// && TXMEditor.this.getResult().hasVisibleChild() && !MessageDialog.openQuestion(getShell(), TXMCoreMessages.common_warning, |
|
943 |
// TXMUIMessages.warning_popup_allDescendantResultsWillBeUpdated)) { |
|
944 |
// setCanceled(true); |
|
945 |
// } |
|
894 | 946 |
// |
895 |
// }
|
|
947 |
// }
|
|
896 | 948 |
} |
897 | 949 |
}); |
898 |
|
|
899 |
if (this.isCanceled()) { |
|
900 |
return Status.CANCEL_STATUS; |
|
901 |
} |
|
902 |
|
|
950 |
|
|
951 |
if (this.isCanceled()) { return Status.CANCEL_STATUS; } |
|
952 |
|
|
903 | 953 |
// computing result |
904 | 954 |
monitor.beginTask(TXMUIMessages.computing_3, 100); |
905 |
|
|
906 |
notifyExtensions("notifyStartOfCompute"); //$NON-NLS-1$
|
|
907 |
|
|
955 |
|
|
956 |
notifyExtensions("notifyStartOfCompute"); //$NON-NLS-1$ |
|
957 |
|
|
908 | 958 |
// user log info |
909 | 959 |
if (update && TXMEditor.this.getResult().canCompute() && !TXMEditor.this.getResult().getComputingStartMessage().isEmpty()) { |
910 | 960 |
Log.info(TXMEditor.this.getResult().getComputingStartMessage()); |
... | ... | |
914 | 964 |
Log.fine("TXMEditor.compute(): " + TXMEditor.this.getClass().getSimpleName() + ": computing failed."); |
915 | 965 |
} |
916 | 966 |
// user log info |
917 |
else if (update && !TXMEditor.this.getResult().getComputingDoneMessage().isEmpty()) {
|
|
967 |
else if (update && !TXMEditor.this.getResult().getComputingDoneMessage().isEmpty()) {
|
|
918 | 968 |
Log.info(TXMEditor.this.getResult().getComputingDoneMessage()); |
919 | 969 |
} |
920 | 970 |
|
921 |
|
|
971 |
|
|
922 | 972 |
notifyExtensions("notifyEndOfCompute"); //$NON-NLS-1$ |
923 |
|
|
973 |
|
|
924 | 974 |
monitor.worked(50); |
925 |
|
|
975 |
|
|
926 | 976 |
// refreshing the UI |
927 | 977 |
this.syncExec(new Runnable() { |
978 |
|
|
928 | 979 |
@Override |
929 | 980 |
public void run() { |
981 |
|
|
930 | 982 |
try { |
931 | 983 |
refresh(update); |
932 |
|
|
933 |
// focus in the main widget
|
|
984 |
|
|
985 |
// focus in the main widget |
|
934 | 986 |
setFocus(); |
935 | 987 |
|
936 | 988 |
StatusLine.setMessage(null); |
937 |
|
|
989 |
|
|
938 | 990 |
// FIXME: SJ: tests to enable/disable the editor widgets when computing |
939 |
//recursiveSetEnabled(true); |
|
991 |
// recursiveSetEnabled(true);
|
|
940 | 992 |
|
941 |
} catch (Exception e) { |
|
993 |
} |
|
994 |
catch (Exception e) { |
|
942 | 995 |
Log.finer("TXMEditor.compute(): " + TXMEditor.this.getClass().getSimpleName() + ": Error while refreshing the editor: " + e); //$NON-NLS-1$ |
943 | 996 |
Log.printStackTrace(e); |
944 | 997 |
} |
... | ... | |
964 | 1017 |
}; |
965 | 1018 |
job.setPriority(Job.DECORATE); |
966 | 1019 |
// FIXME: SJ tests |
967 |
//job.setPriority(Job.INTERACTIVE); |
|
1020 |
// job.setPriority(Job.INTERACTIVE);
|
|
968 | 1021 |
job.setUser(true); |
969 | 1022 |
job.schedule(); |
970 |
|
|
1023 |
|
|
971 | 1024 |
return job; |
972 | 1025 |
} |
973 |
|
|
1026 |
|
|
974 | 1027 |
/** |
975 | 1028 |
* Opens an editor specified by its id, computes the specified result then refreshes the editor components. |
976 | 1029 |
* If the editor was already opened, the computing is skipped and the focus is given to the editor. |
... | ... | |
978 | 1031 |
* @param result |
979 | 1032 |
* @param editorPartId |
980 | 1033 |
*/ |
981 |
public static TXMEditor openEditor(TXMResult result, String editorPartId) { |
|
1034 |
public static TXMEditor openEditor(TXMResult result, String editorPartId) { |
|
1035 |
|
|
982 | 1036 |
return openEditor(new TXMResultEditorInput<TXMResult>(result), editorPartId); |
983 | 1037 |
} |
984 |
|
|
985 |
|
|
1038 |
|
|
986 | 1039 |
/** |
987 | 1040 |
* Opens an editor specified by its id, computes the result stored in the specified editor input then refreshes the editor components. |
988 | 1041 |
* If the editor was already opened, the computing is skipped and the focus is given to the editor. |
1042 |
* |
|
989 | 1043 |
* @param editorInput |
990 | 1044 |
* @param editorId |
991 | 1045 |
* @return |
992 | 1046 |
*/ |
993 | 1047 |
@SuppressWarnings("unchecked") |
994 |
public static TXMEditor<? extends TXMResult> openEditor(TXMResultEditorInput<? extends TXMResult> editorInput, String editorId) { |
|
1048 |
public static TXMEditor<? extends TXMResult> openEditor(TXMResultEditorInput<? extends TXMResult> editorInput, String editorId) { |
|
1049 |
|
|
995 | 1050 |
TXMEditor<? extends TXMResult> editor = null; |
996 | 1051 |
IWorkbenchWindow window = TXMWindows.getActiveWindow(); |
997 | 1052 |
IWorkbenchPage page = window.getActivePage(); |
... | ... | |
1006 | 1061 |
else { |
1007 | 1062 |
return null; |
1008 | 1063 |
} |
1009 |
|
|
1064 |
|
|
1010 | 1065 |
if (wasAlreadyOpened) { |
1011 | 1066 |
|
1012 |
} else { |
|
1013 |
//TODO until the TXMResult don't know if its parameters are set by the user or by the default preference value, we need to use the AUTO_COMPUTE_ON_EDITOR_OPEN preference |
|
1067 |
} |
|
1068 |
else { |
|
1069 |
// TODO until the TXMResult don't know if its parameters are set by the user or by the default preference value, we need to use the AUTO_COMPUTE_ON_EDITOR_OPEN preference |
|
1014 | 1070 |
// compute the result only if the editor wasn't already opened |
1015 |
if ((RCPPreferences.getInstance().getBoolean(RCPPreferences.AUTO_COMPUTE_ON_EDITOR_OPEN))) {
|
|
1071 |
if ((RCPPreferences.getInstance().getBoolean(RCPPreferences.AUTO_COMPUTE_ON_EDITOR_OPEN))) {
|
|
1016 | 1072 |
editor.compute(false); |
1017 |
} else { |
|
1073 |
} |
|
1074 |
else { |
|
1018 | 1075 |
editor.refresh(false); |
1019 | 1076 |
} |
1020 | 1077 |
} |
... | ... | |
1025 | 1082 |
} |
1026 | 1083 |
return editor; |
1027 | 1084 |
} |
1028 |
|
|
1085 |
|
|
1029 | 1086 |
/** |
1030 | 1087 |
* Synchronizes the editor from the result and refreshes the corpus view. |
1031 | 1088 |
* Also fires a dirty property change. |
1089 |
* |
|
1032 | 1090 |
* @param update |
1033 |
* @throws Exception
|
|
1091 |
* @throws Exception |
|
1034 | 1092 |
*/ |
1035 | 1093 |
public final void refresh(boolean update) throws Exception { |
1094 |
|
|
1036 | 1095 |
if (this.parent.isDisposed()) return; // nothing to refresh |
1037 | 1096 |
|
1038 | 1097 |
// skip refresh if the part creation has failed |
1039 |
if (!createPartControlDoneSucessfully) { |
|
1040 |
return; |
|
1041 |
} |
|
1042 |
|
|
1043 |
//this.parent.setRedraw(false); |
|
1098 |
if (!createPartControlDoneSucessfully) { return; } |
|
1044 | 1099 |
|
1100 |
// this.parent.setRedraw(false); |
|
1101 |
|
|
1045 | 1102 |
this.notifyExtensions("notifyStartOfRefresh"); //$NON-NLS-1$ |
1046 |
|
|
1103 |
|
|
1047 | 1104 |
TXMResult result = this.getResult(); |
1048 |
|
|
1105 |
|
|
1049 | 1106 |
// disable the component rendering to avoid strange behaviors when modifying the result area widget |
1050 |
//this.getContainer().setRedraw(false); |
|
1051 |
|
|
1107 |
// this.getContainer().setRedraw(false);
|
|
1108 |
|
|
1052 | 1109 |
String title = result.getName(); |
1053 | 1110 |
if (title.length() > 41) { // limit title length |
1054 |
title = title.substring(0, 40)+"...";
|
|
1111 |
title = title.substring(0, 40) + "...";
|
|
1055 | 1112 |
} |
1056 | 1113 |
this.setPartName(title); |
1057 |
//this.firePropertyChange(TXMEditor.PROP_DIRTY); |
|
1058 |
|
|
1059 |
//MD commented 'if (!update) {...}' |
|
1114 |
// this.firePropertyChange(TXMEditor.PROP_DIRTY);
|
|
1115 |
|
|
1116 |
// MD commented 'if (!update) {...}'
|
|
1060 | 1117 |
// SJ need to check all works, it also was dedicated to not refresh the Editor from result after a computing, it's not needed since the computing has been done |
1061 | 1118 |
// from fields themselves |
1062 |
//if (!update) { |
|
1119 |
// if (!update) {
|
|
1063 | 1120 |
// FIXME: debug |
1064 | 1121 |
Log.finest("TXMEditor.refresh(): " + this.getClass().getSimpleName() + ": auto updating editor from result."); //$NON-NLS-1$ |
1065 | 1122 |
this.autoUpdateEditorFieldsFromResult(update); // auto update from Parameter annotations |
1066 |
|
|
1123 |
|
|
1067 | 1124 |
// FIXME: debug |
1068 | 1125 |
Log.finest("TXMEditor.refresh(): " + this.getClass().getSimpleName() + ": updating subclass editor from result."); //$NON-NLS-1$ //$NON-NLS-2$ |
1069 | 1126 |
this.updateEditorFromResult(update); // subclasses manual settings |
1070 |
//} |
|
1071 |
|
|
1127 |
// }
|
|
1128 |
|
|
1072 | 1129 |
// Hide the computing parameter area if the editor wasn't open and the result is computed |
1073 | 1130 |
if (!update && !result.isDirty() && !this.topToolBar.isDisposed()) { |
1074 | 1131 |
this.topToolBar.setComputingParametersVisible(false); |
1075 | 1132 |
} |
1076 |
|
|
1133 |
|
|
1077 | 1134 |
if (!topToolBar.isDisposed()) this.topToolBar.redraw(); |
1078 |
|
|
1135 |
|
|
1079 | 1136 |
CorporaView.refreshObject(this); |
1080 | 1137 |
TXMResultDebugView.refreshView(); |
1081 |
|
|
1138 |
|
|
1082 | 1139 |
// re-enable the component rendering |
1083 | 1140 |
this.getContainer().setRedraw(true); |
1084 |
|
|
1141 |
|
|
1085 | 1142 |
// FIXME: SJ: this code breaks the dirty/chart dirty separation state, eg. if a non electric rendering parameter is changed then the chart is dirty but not the result, need to check this |
1086 | 1143 |
this.setDirty(this.getResult().isDirty()); |
1087 |
|
|
1144 |
|
|
1088 | 1145 |
// FIXME: update all open editors of the children result but also of the result itself |
1089 | 1146 |
// FIXME: debug |
1090 | 1147 |
Log.finest("TXMEditor.refresh(): " + this.getClass().getSimpleName() + ": synchronizing and refreshing result children opened editors."); //$NON-NLS-1$ //$NON-NLS-2$ |
1091 |
|
|
1148 |
|
|
1092 | 1149 |
List<TXMResult> results = this.getResult().getDeepChildren(); |
1093 |
|
|
1150 |
|
|
1094 | 1151 |
for (int i = 0; i < results.size(); i++) { |
1095 |
ArrayList<ITXMResultEditor<?>> editors = SWTEditorsUtils.getEditors(results.get(i)) ;
|
|
1152 |
ArrayList<ITXMResultEditor<?>> editors = SWTEditorsUtils.getEditors(results.get(i)); |
|
1096 | 1153 |
for (int j = 0; j < editors.size(); j++) { |
1097 | 1154 |
ITXMResultEditor<?> txmEditor = editors.get(j); |
1098 |
if(txmEditor != this |
|
1099 |
//&& txmEditor.isDirty()
|
|
1100 |
) {
|
|
1101 |
//txmEditor.synchronizeResultFromEditor(); |
|
1102 |
|
|
1155 |
if (txmEditor != this
|
|
1156 |
// && txmEditor.isDirty()
|
|
1157 |
) {
|
|
1158 |
// txmEditor.synchronizeResultFromEditor();
|
|
1159 |
|
|
1103 | 1160 |
// FIXME: SJ: need to prove/test this code |
1104 |
// recreate all if the parent result is altered
|
|
1105 |
//txmEditor.refresh(!this.getResult().isAltered()); |
|
1161 |
// recreate all if the parent result is altered |
|
1162 |
// txmEditor.refresh(!this.getResult().isAltered());
|
|
1106 | 1163 |
txmEditor.refresh(true); |
1107 | 1164 |
} |
1108 | 1165 |
} |
1109 | 1166 |
} |
1110 |
|
|
1167 |
|
|
1111 | 1168 |
this.notifyExtensions("notifyEndOfRefresh"); //$NON-NLS-1$ |
1112 | 1169 |
|
1113 | 1170 |
// re-enable the rendering that has been disabled in createPartControl() |
1114 | 1171 |
// FIXME: SJ: would be very nice to do that to avoid to see the empty tables before the refresh() that fill the UI. |
1115 | 1172 |
// the disabling is done in createPartControl() but the EditionEditor doesn't seem to call refresh() so it breaks it |
1116 |
//this.parent.setRedraw(true); |
|
1173 |
// this.parent.setRedraw(true);
|
|
1117 | 1174 |
} |
1118 |
|
|
1175 |
|
|
1119 | 1176 |
/** |
1120 | 1177 |
* Synchronizes the result parameters with editor widgets. |
1121 | 1178 |
* <p> |
1122 | 1179 |
* It should be called or called itself in the UI thread when accessing Widget parameters. |
1123 | 1180 |
*/ |
1124 | 1181 |
public abstract void updateResultFromEditor(); |
1125 |
|
|
1182 |
|
|
1126 | 1183 |
/** |
1127 |
* Synchronizes the editor widgets with the result parameters.
|
|
1184 |
* Synchronizes the editor widgets with the result parameters. |
|
1128 | 1185 |
* Dedicated to dynamically change the editor components from the stored result. |
1129 | 1186 |
* |
1130 | 1187 |
* Use this method if you need to save parameter with Type not managed by the autoUpdateEditorFieldsFromResult method. |
1131 |
* @throws Exception |
|
1188 |
* |
|
1189 |
* @throws Exception |
|
1132 | 1190 |
*/ |
1133 | 1191 |
public abstract void updateEditorFromResult(boolean update) throws Exception; |
1134 |
|
|
1135 |
|
|
1136 |
|
|
1192 |
|
|
1193 |
|
|
1194 |
|
|
1137 | 1195 |
/** |
1138 | 1196 |
* Updates the editor fields from TXMResult and declared parameters annotations in both TXMEditor and TXMResult. |
1139 | 1197 |
* Manages these widgets at this moment: |
1140 |
*
|
|
1141 |
* ToolItem (Boolean)
|
|
1142 |
* FloatSpinner (Float)
|
|
1143 |
* Spinner (Integer)
|
|
1144 |
* Text (String),
|
|
1198 |
* |
|
1199 |
* ToolItem (Boolean) |
|
1200 |
* FloatSpinner (Float) |
|
1201 |
* Spinner (Integer) |
|
1202 |
* Text (String), |
|
1145 | 1203 |
* Button (Boolean) |
1146 | 1204 |
* Viewer (Object) |
1147 | 1205 |
* PropertiesSelector (Property and List<Property>) |
... | ... | |
1150 | 1208 |
* QueryWidget (String, from Query) |
1151 | 1209 |
* |
1152 | 1210 |
*/ |
1153 |
public void autoUpdateEditorFieldsFromResult(boolean update) {
|
|
1154 |
|
|
1211 |
public void autoUpdateEditorFieldsFromResult(boolean update) {
|
|
1212 |
|
|
1155 | 1213 |
List<Field> fields = this.getAllParameterFields(); |
1156 |
|
|
1214 |
|
|
1157 | 1215 |
for (Field f : fields) { |
1158 | 1216 |
Parameter parameter = f.getAnnotation(Parameter.class); |
1159 | 1217 |
if (parameter == null || parameter.key().isEmpty()) { |
1160 | 1218 |
continue; |
1161 | 1219 |
} |
1162 |
|
|
1220 |
|
|
1163 | 1221 |
Object object = null; |
1164 | 1222 |
Object value = null; |
1165 |
|
|
1223 |
|
|
1166 | 1224 |
try { |
1167 | 1225 |
f.setAccessible(true); |
1168 | 1226 |
object = f.get(this); |
1169 | 1227 |
|
1170 | 1228 |
// propagate to all parents |
1171 | 1229 |
value = this.getResult().getParameter(parameter.key(), true); |
1172 |
|
|
1230 |
|
|
1173 | 1231 |
if (value == null) { |
1174 |
//System.out.println("Warning: "+this.getPartName()+" result "+this.getResult()+" "+parameter.key()+" is not initialized."); |
|
1232 |
// System.out.println("Warning: "+this.getPartName()+" result "+this.getResult()+" "+parameter.key()+" is not initialized.");
|
|
1175 | 1233 |
continue; // not initialized |
1176 | 1234 |
} |
1177 |
if(object instanceof ToolItem) {
|
|
1178 |
((ToolItem)object).setSelection((Boolean) value);
|
|
1235 |
if (object instanceof ToolItem) {
|
|
1236 |
((ToolItem) object).setSelection((Boolean) value);
|
|
1179 | 1237 |
} |
1180 |
else if(object instanceof FloatSpinner) {
|
|
1181 |
|
|
1182 |
((FloatSpinner)object).setData(BaseAbstractComputeListener.IGNORE_EVENT, true); |
|
1183 |
|
|
1184 |
if(value instanceof Double) { |
|
1185 |
((FloatSpinner)object).setSelection((Double) value);
|
|
1238 |
else if (object instanceof FloatSpinner) {
|
|
1239 |
|
|
1240 |
((FloatSpinner) object).setData(BaseAbstractComputeListener.IGNORE_EVENT, true);
|
|
1241 |
|
|
1242 |
if (value instanceof Double) {
|
|
1243 |
((FloatSpinner) object).setSelection((Double) value);
|
|
1186 | 1244 |
} |
1187 | 1245 |
else { |
1188 |
((FloatSpinner)object).setSelection((Float) value); |
|
1246 |
((FloatSpinner) object).setSelection((Float) value);
|
|
1189 | 1247 |
} |
1190 |
|
|
1191 |
((FloatSpinner)object).setData(BaseAbstractComputeListener.IGNORE_EVENT, false); |
|
1248 |
|
|
1249 |
((FloatSpinner) object).setData(BaseAbstractComputeListener.IGNORE_EVENT, false);
|
|
1192 | 1250 |
} |
1193 |
else if(object instanceof Spinner) {
|
|
1194 |
((Spinner)object).setData(BaseAbstractComputeListener.IGNORE_EVENT, true); |
|
1195 |
((Spinner)object).setSelection((Integer) value);
|
|
1196 |
((Spinner)object).setData(BaseAbstractComputeListener.IGNORE_EVENT, false); |
|
1251 |
else if (object instanceof Spinner) {
|
|
1252 |
((Spinner) object).setData(BaseAbstractComputeListener.IGNORE_EVENT, true);
|
|
1253 |
((Spinner) object).setSelection((Integer) value);
|
|
1254 |
((Spinner) object).setData(BaseAbstractComputeListener.IGNORE_EVENT, false);
|
|
1197 | 1255 |
} |
1198 |
else if(object instanceof Text) {
|
|
1199 |
((Text)object).setText(String.valueOf(value));
|
|
1256 |
else if (object instanceof Text) {
|
|
1257 |
((Text) object).setText(String.valueOf(value));
|
|
1200 | 1258 |
} |
Formats disponibles : Unified diff