1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Intel Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * Intel Corporation - Initial API and implementation
10 * Andrew Gvozdev (Quoin Inc.) - Regular expression error parsers
11 *******************************************************************************/
12 package org.eclipse.cdt.ui.newui;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.HashMap;
18 import java.util.LinkedHashMap;
19 import java.util.LinkedHashSet;
20 import java.util.List;
24 import org.eclipse.core.runtime.Assert;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IStatus;
27 import org.eclipse.core.runtime.NullProgressMonitor;
28 import org.eclipse.jface.dialogs.MessageDialog;
29 import org.eclipse.jface.layout.PixelConverter;
30 import org.eclipse.jface.viewers.CheckStateChangedEvent;
31 import org.eclipse.jface.viewers.CheckboxTableViewer;
32 import org.eclipse.jface.viewers.ICheckStateListener;
33 import org.eclipse.jface.viewers.IDecoration;
34 import org.eclipse.jface.viewers.IStructuredContentProvider;
35 import org.eclipse.jface.viewers.LabelProvider;
36 import org.eclipse.jface.viewers.Viewer;
37 import org.eclipse.jface.window.Window;
38 import org.eclipse.osgi.util.NLS;
39 import org.eclipse.swt.SWT;
40 import org.eclipse.swt.custom.SashForm;
41 import org.eclipse.swt.events.SelectionAdapter;
42 import org.eclipse.swt.events.SelectionEvent;
43 import org.eclipse.swt.graphics.Image;
44 import org.eclipse.swt.layout.GridData;
45 import org.eclipse.swt.layout.GridLayout;
46 import org.eclipse.swt.widgets.Composite;
47 import org.eclipse.swt.widgets.Event;
48 import org.eclipse.swt.widgets.Listener;
49 import org.eclipse.swt.widgets.Table;
50 import org.eclipse.swt.widgets.TableItem;
51 import org.eclipse.ui.PlatformUI;
52 import org.osgi.service.prefs.BackingStoreException;
54 import com.ibm.icu.text.MessageFormat;
56 import org.eclipse.cdt.core.CCorePlugin;
57 import org.eclipse.cdt.core.ErrorParserManager;
58 import org.eclipse.cdt.core.IErrorParserNamed;
59 import org.eclipse.cdt.core.errorparsers.RegexErrorParser;
60 import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
61 import org.eclipse.cdt.core.settings.model.ICMultiConfigDescription;
62 import org.eclipse.cdt.core.settings.model.ICResourceDescription;
63 import org.eclipse.cdt.ui.CDTSharedImages;
64 import org.eclipse.cdt.ui.CUIPlugin;
65 import org.eclipse.cdt.ui.dialogs.ICOptionPage;
66 import org.eclipse.cdt.ui.dialogs.IInputStatusValidator;
67 import org.eclipse.cdt.ui.dialogs.InputStatusDialog;
68 import org.eclipse.cdt.ui.dialogs.RegexErrorParserOptionPage;
69 import org.eclipse.cdt.utils.ui.controls.TabFolderLayout;
71 import org.eclipse.cdt.internal.ui.ICHelpContextIds;
72 import org.eclipse.cdt.internal.ui.dialogs.StatusInfo;
73 import org.eclipse.cdt.internal.ui.newui.Messages;
77 * This class represents Error Parser Tab in Project Properties or workspace Preferences
79 * @noextend This class is not intended to be subclassed by clients.
81 public class ErrorParsTab extends AbstractCPropertyTab {
82 private static final int DEFAULT_HEIGHT = 130;
83 private static final int BUTTON_ADD = 0;
84 private static final int BUTTON_EDIT = 1;
85 private static final int BUTTON_DELETE = 2;
86 // there is a separator instead of button = 3
87 private static final int BUTTON_MOVEUP = 4;
88 private static final int BUTTON_MOVEDOWN = 5;
90 private static final String[] BUTTONS = new String[] {
98 private static final String RESET_STR = Messages.ErrorParsTab_Reset;
100 private static final String OOPS = "OOPS"; //$NON-NLS-1$
102 private Table fTable;
103 private CheckboxTableViewer fTableViewer;
104 private ICConfigurationDescription fCfgDesc;
106 private static Map<String, IErrorParserNamed> fExtensionErrorParsers = null;
108 private final Map<String, IErrorParserNamed> fAvailableErrorParsers = new LinkedHashMap<String, IErrorParserNamed>();
109 private final Map<String, ICOptionPage> fOptionsPageMap = new HashMap<String, ICOptionPage>();
110 private ICOptionPage fCurrentOptionsPage = null;
112 private Composite fCompositeForOptionsPage;
115 * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#createControls(org.eclipse.swt.widgets.Composite)
118 public void createControls(Composite parent) {
120 super.createControls(parent);
121 PlatformUI.getWorkbench().getHelpSystem().setHelp(usercomp, ICHelpContextIds.ERROR_PARSERS_PAGE);
123 usercomp.setLayout(new GridLayout(1, false));
126 SashForm sashForm = new SashForm(usercomp, SWT.NONE);
127 sashForm.setBackground(sashForm.getDisplay().getSystemColor(SWT.COLOR_GRAY));
128 sashForm.setOrientation(SWT.VERTICAL);
129 sashForm.setLayoutData(new GridData(GridData.FILL_BOTH));
131 GridLayout layout = new GridLayout(2, false);
132 layout.marginHeight = 5;
133 sashForm.setLayout(layout);
136 Composite compositeSashForm = new Composite(sashForm, SWT.NONE);
137 compositeSashForm.setLayout(new GridLayout(2, false));
138 fTable = new Table(compositeSashForm, SWT.BORDER | SWT.CHECK | SWT.SINGLE);
139 fTable.setLayoutData(new GridData(GridData.FILL_BOTH));
140 fTable.addSelectionListener(new SelectionAdapter() {
142 public void widgetSelected(SelectionEvent e) {
143 displaySelectedOptionPage();
146 fTableViewer = new CheckboxTableViewer(fTable);
147 fTableViewer.setContentProvider(new IStructuredContentProvider() {
148 public Object[] getElements(Object inputElement) {
149 return (Object[])inputElement;
151 public void dispose() {}
152 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
154 fTableViewer.setLabelProvider(new LabelProvider() {
156 public String getText(Object element) {
157 if (element instanceof String) {
158 String id = (String)element;
159 IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
160 if (errorParser!=null) {
161 String name = errorParser.getName();
162 if (name!=null && name.length()>0) {
166 return NLS.bind(Messages.ErrorParsTab_error_NonAccessibleID, id);
172 public Image getImage(Object element) {
173 final String TEST_PLUGIN_ID = "org.eclipse.cdt.core.tests"; //$NON-NLS-1$
174 final String DEPRECATED = CCorePlugin.getResourceString("CCorePlugin.Deprecated"); //$NON-NLS-1$
175 if (element instanceof String) {
176 String id = (String) element;
177 String[] extIds = ErrorParserManager.getErrorParserExtensionIds();
178 if (Arrays.asList(extIds).contains(id)) {
179 String imageKey = CDTSharedImages.IMG_OBJS_EXTENSION;
180 if (id.startsWith(TEST_PLUGIN_ID))
181 imageKey = CDTSharedImages.IMG_OBJS_CDT_TESTING;
183 String[] overlayKeys = new String[5];
184 IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
185 IErrorParserNamed errorParserExt = fExtensionErrorParsers.get(id);
186 if (!errorParser.equals(errorParserExt)) {
187 overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_SETTING;
188 } else if (errorParser.getName().contains(DEPRECATED)) {
189 overlayKeys[IDecoration.TOP_RIGHT] = CDTSharedImages.IMG_OVR_INACTIVE;
191 return CDTSharedImages.getImageOverlaid(imageKey, overlayKeys);
193 return CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_USER);
200 fTableViewer.addCheckStateListener(new ICheckStateListener() {
201 public void checkStateChanged(CheckStateChangedEvent e) {
206 Composite compositeButtons = new Composite(compositeSashForm, SWT.NONE);
207 compositeButtons.setLayoutData(new GridData(GridData.END));
208 initButtons(compositeButtons, BUTTONS);
210 fCompositeForOptionsPage = new Composite(sashForm, SWT.NULL);
211 GridData gd = new GridData();
212 fCompositeForOptionsPage.setLayout(new TabFolderLayout());
214 PixelConverter converter = new PixelConverter(parent);
215 gd.heightHint = converter.convertHorizontalDLUsToPixels(DEFAULT_HEIGHT);
217 gd.horizontalAlignment = GridData.FILL;
218 gd.grabExcessHorizontalSpace = true;
219 gd.grabExcessVerticalSpace = true;
220 gd.horizontalSpan = 2;
221 fCompositeForOptionsPage.setLayoutData(gd);
223 sashForm.setWeights(new int[] {50, 50});
226 ICResourceDescription resDecs = getResDesc();
227 fCfgDesc = resDecs!=null ? resDecs.getConfiguration() : null;
229 updateData(getResDesc());
232 private void initMapParsers() {
233 if (fExtensionErrorParsers==null) {
234 fExtensionErrorParsers = new LinkedHashMap<String, IErrorParserNamed>();
235 String[] idsExt = ErrorParserManager.getErrorParserExtensionIds();
236 for (String idExt : idsExt) {
237 IErrorParserNamed errorParserExt = ErrorParserManager.getErrorParserExtensionCopy(idExt);
238 fExtensionErrorParsers.put(idExt, errorParserExt);
241 fAvailableErrorParsers.clear();
242 fOptionsPageMap.clear();
243 for (String id : ErrorParserManager.getErrorParserAvailableIds()) {
244 IErrorParserNamed errorParser = ErrorParserManager.getErrorParserCopy(id);
245 fAvailableErrorParsers.put(id, errorParser);
246 initializeOptionsPage(id);
250 if (fCfgDesc!=null) {
251 ICConfigurationDescription srcCfgDesc = fCfgDesc.getConfiguration();
252 if (srcCfgDesc instanceof ICMultiConfigDescription) {
253 String[][] ss = ((ICMultiConfigDescription)srcCfgDesc).getErrorParserIDs();
254 ids = CDTPrefUtil.getStrListForDisplay(ss);
256 ids = srcCfgDesc.getBuildSetting().getErrorParserIDs();
258 Set<String> setIds = new LinkedHashSet<String>(Arrays.asList(ids));
259 setIds.addAll(fAvailableErrorParsers.keySet());
260 fTableViewer.setInput(setIds.toArray(new String[0]));
262 fTableViewer.setInput(fAvailableErrorParsers.keySet().toArray(new String[0]));
263 ids = ErrorParserManager.getDefaultErrorParserIds();
265 fTableViewer.setCheckedElements(ids);
267 displaySelectedOptionPage();
270 private void initializeOptionsPage(final String id) {
271 IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
272 if (errorParser!=null) {
273 String name = errorParser.getName();
274 if (name!=null && name.length()>0) {
275 // RegexErrorParser has an Options page
276 if (errorParser instanceof RegexErrorParser) {
277 // allow to edit only for Build Settings Preference Page (where cfgd==null)
278 RegexErrorParserOptionPage optionsPage = new RegexErrorParserOptionPage((RegexErrorParser) errorParser, isErrorParsersEditable());
279 optionsPage.addListener(new Listener() {
280 public void handleEvent(Event event) {
281 fTableViewer.refresh(id);
285 fOptionsPageMap.put(id, optionsPage);
286 optionsPage.setContainer(page);
287 optionsPage.createControl(fCompositeForOptionsPage);
288 optionsPage.setVisible(false);
289 fCompositeForOptionsPage.layout(true);
295 private void displaySelectedOptionPage() {
296 if (fCurrentOptionsPage != null)
297 fCurrentOptionsPage.setVisible(false);
299 int pos = fTable.getSelectionIndex();
303 String parserId = (String)fTable.getItem(pos).getData();
304 ICOptionPage optionsPage = fOptionsPageMap.get(parserId);
305 if (optionsPage != null) {
306 optionsPage.setVisible(true);
308 fCurrentOptionsPage = optionsPage;
312 * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#buttonPressed(int)
315 public void buttonPressed (int n) {
329 case BUTTON_MOVEDOWN:
338 // Move item up / down
339 private void moveItem(boolean up) {
340 int n = fTable.getSelectionIndex();
341 if (n < 0 || (up && n == 0) || (!up && n+1 == fTable.getItemCount()))
344 String id = (String)fTableViewer.getElementAt(n);
345 boolean checked = fTableViewer.getChecked(id);
346 fTableViewer.remove(id);
348 fTableViewer.insert(id, n);
349 fTableViewer.setChecked(id, checked);
350 fTable.setSelection(n);
355 private String makeId(String name) {
356 return CUIPlugin.PLUGIN_ID+'.'+name;
359 private void addErrorParser() {
360 IInputStatusValidator inputValidator = new IInputStatusValidator() {
361 public IStatus isValid(String newText) {
362 StatusInfo status = new StatusInfo();
363 if (newText.trim().length() == 0) {
364 status.setError(Messages.ErrorParsTab_error_NonEmptyName);
365 } else if (newText.indexOf(ErrorParserManager.ERROR_PARSER_DELIMITER)>=0) {
366 String message = MessageFormat.format( Messages.ErrorParsTab_error_IllegalCharacter,
367 new Object[] { ErrorParserManager.ERROR_PARSER_DELIMITER });
368 status.setError(message);
369 } else if (fAvailableErrorParsers.containsKey(makeId(newText))) {
370 status.setError(Messages.ErrorParsTab_error_NonUniqueID);
376 InputStatusDialog addDialog = new InputStatusDialog(usercomp.getShell(),
377 Messages.ErrorParsTab_title_Add,
378 Messages.ErrorParsTab_label_EnterName,
379 Messages.ErrorParsTab_label_DefaultRegexErrorParserName,
381 addDialog.setHelpAvailable(false);
383 if (addDialog.open() == Window.OK) {
384 String newName = addDialog.getValue();
385 String newId = makeId(newName);
386 IErrorParserNamed errorParser = new RegexErrorParser(newId, newName);
387 fAvailableErrorParsers.put(newId, errorParser);
389 fTableViewer.add(newId);
390 fTableViewer.setChecked(newId, true);
391 fTable.setSelection(fTable.getItemCount()-1);
393 initializeOptionsPage(newId);
394 displaySelectedOptionPage();
399 private void editErrorParser() {
400 int n = fTable.getSelectionIndex();
403 String id = (String)fTableViewer.getElementAt(n);
404 IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
406 IInputStatusValidator inputValidator = new IInputStatusValidator() {
407 public IStatus isValid(String newText) {
408 StatusInfo status = new StatusInfo();
409 if (newText.trim().length() == 0) {
410 status.setError(Messages.ErrorParsTab_error_NonEmptyName);
411 } else if (newText.indexOf(ErrorParserManager.ERROR_PARSER_DELIMITER)>=0) {
412 String message = MessageFormat.format( Messages.ErrorParsTab_error_IllegalCharacter,
413 new Object[] { ErrorParserManager.ERROR_PARSER_DELIMITER });
414 status.setError(message);
420 InputStatusDialog addDialog = new InputStatusDialog(usercomp.getShell(),
421 Messages.ErrorParsTab_title_Edit,
422 Messages.ErrorParsTab_label_EnterName,
423 errorParser.getName(),
425 addDialog.setHelpAvailable(false);
427 if (addDialog.open() == Window.OK) {
428 errorParser.setName(addDialog.getValue());
429 fTableViewer.refresh(id);
433 private void deleteErrorParser() {
434 int n = fTable.getSelectionIndex();
438 String id = (String)fTableViewer.getElementAt(n);
439 if (fExtensionErrorParsers.containsKey(id)) {
441 fAvailableErrorParsers.put(id, ErrorParserManager.getErrorParserExtensionCopy(id));
442 fTableViewer.refresh(id);
443 initializeOptionsPage(id);
444 displaySelectedOptionPage();
447 fTableViewer.remove(id);
449 int last = fTable.getItemCount() - 1;
453 fTable.setSelection(n);
460 * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#updateData(org.eclipse.cdt.core.settings.model.ICResourceDescription)
463 public void updateData(ICResourceDescription resDecs) {
464 ICConfigurationDescription oldCfgDesc = fCfgDesc;
465 fCfgDesc = resDecs!=null ? resDecs.getConfiguration() : null;
466 if (oldCfgDesc!=fCfgDesc) {
469 displaySelectedOptionPage();
473 private static boolean isExtensionId(String id) {
474 for (String extId : ErrorParserManager.getErrorParserExtensionIds()) {
475 if (extId.equals(id)) {
483 * Check if error parser with this id shown to user differs from error parser defined as extension.
485 private boolean isModified(String id) {
486 IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
487 IErrorParserNamed errorParserExt = fExtensionErrorParsers.get(id);
488 return ! errorParser.equals(errorParserExt);
492 * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#updateButtons()
495 public void updateButtons() {
496 int pos = fTable.getSelectionIndex();
497 int count = fTable.getItemCount();
498 int last = count - 1;
499 boolean selected = pos >= 0 && pos <= last;
500 String id = (String)fTableViewer.getElementAt(pos);
502 boolean isExtensionId = isExtensionId(id);
503 boolean canDelete = !isExtensionId && isErrorParsersEditable();
504 boolean canReset = isExtensionId && isErrorParsersEditable() && isModified(id);
506 buttonSetText(BUTTON_DELETE, isExtensionId ? RESET_STR : DEL_STR);
508 buttonSetEnabled(BUTTON_ADD, isErrorParsersEditable());
509 buttonSetEnabled(BUTTON_EDIT, isErrorParsersEditable() && selected);
510 buttonSetEnabled(BUTTON_DELETE, (canDelete || canReset) && selected);
511 buttonSetEnabled(BUTTON_MOVEUP, selected && pos!=0);
512 buttonSetEnabled(BUTTON_MOVEDOWN, selected && pos!=last);
517 * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#performApply(org.eclipse.cdt.core.settings.model.ICResourceDescription, org.eclipse.cdt.core.settings.model.ICResourceDescription)
520 protected void performApply(ICResourceDescription src, ICResourceDescription dst) {
523 if (!page.isForPrefs()) {
524 ICConfigurationDescription sd = src.getConfiguration();
525 ICConfigurationDescription dd = dst.getConfiguration();
527 if (sd instanceof ICMultiConfigDescription) {
528 String[][] ss = ((ICMultiConfigDescription)sd).getErrorParserIDs();
529 s = CDTPrefUtil.getStrListForDisplay(ss);
531 s = sd.getBuildSetting().getErrorParserIDs();
533 if (dd instanceof ICMultiConfigDescription)
534 ((ICMultiConfigDescription)dd).setErrorParserIDs(s);
536 dd.getBuildSetting().setErrorParserIDs(s);
542 * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#performOK()
545 protected void performOK() {
548 if (page.isForPrefs()) {
549 if (fCfgDesc==null) {
550 // Build Settings page
552 List<IErrorParserNamed> errorParsersList = new ArrayList<IErrorParserNamed>(fTable.getItemCount());
553 for (TableItem item : fTable.getItems()) {
554 if (item.getData() instanceof String) {
555 String id = (String) item.getData();
556 if (isModified(id)) {
557 errorParsersList.add(fAvailableErrorParsers.get(id));
562 Object[] checkedElements = fTableViewer.getCheckedElements();
563 String[] checkedErrorParserIds = new String[checkedElements.length];
564 System.arraycopy(checkedElements, 0, checkedErrorParserIds, 0, checkedElements.length);
566 ErrorParserManager.setDefaultErrorParserIds(checkedErrorParserIds);
567 ErrorParserManager.setUserDefinedErrorParsers(errorParsersList.toArray(new IErrorParserNamed[errorParsersList.size()]));
568 } catch (BackingStoreException e) {
569 CUIPlugin.log(Messages.ErrorParsTab_error_OnApplyingSettings, e);
570 } catch (CoreException e) {
571 CUIPlugin.log(Messages.ErrorParsTab_error_OnApplyingSettings, e);
578 private void saveChecked() {
579 if (fCfgDesc!=null) {
580 Object[] objs = fTableViewer.getCheckedElements();
581 String[] ids = new String[objs.length];
582 System.arraycopy(objs, 0, ids, 0, objs.length);
584 if (fCfgDesc instanceof ICMultiConfigDescription)
585 ((ICMultiConfigDescription)fCfgDesc).setErrorParserIDs(ids);
587 fCfgDesc.getBuildSetting().setErrorParserIDs(ids);
592 * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#canBeVisible()
595 public boolean canBeVisible() {
596 return page.isForProject() || page.isForPrefs();
600 * @return {@code true} if the error parsers are allowed to be editable,
601 * i.e. Add/Edit/Delete buttons are enabled and Options page edits enabled.
602 * This will evaluate to {@code true} for Preference Build Settings page but
603 * not for Preference New CDT Project Wizard/Makefile Project.
605 private boolean isErrorParsersEditable() {
606 return fCfgDesc==null;
610 * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#performDefaults()
613 protected void performDefaults() {
614 if (isErrorParsersEditable()) {
615 // Must be Build Settings Preference Page
616 if (MessageDialog.openQuestion(usercomp.getShell(),
617 Messages.ErrorParsTab_title_ConfirmReset,
618 Messages.ErrorParsTab_message_ConfirmReset)) {
621 ErrorParserManager.setUserDefinedErrorParsers(null);
622 ErrorParserManager.setDefaultErrorParserIds(null);
623 } catch (BackingStoreException e) {
624 CUIPlugin.log(Messages.ErrorParsTab_error_OnRestoring, e);
625 } catch (CoreException e) {
626 CUIPlugin.log(Messages.ErrorParsTab_error_OnRestoring, e);
630 if (fCfgDesc instanceof ICMultiConfigDescription)
631 ((ICMultiConfigDescription) fCfgDesc).setErrorParserIDs(null);
633 fCfgDesc.getBuildSetting().setErrorParserIDs(null);
639 private void informPages(boolean apply) {
640 Collection<ICOptionPage> pages = fOptionsPageMap.values();
641 for (ICOptionPage dynamicPage : pages) {
642 if (dynamicPage!=null && dynamicPage.isValid() && dynamicPage.getControl() != null) {
645 dynamicPage.performApply(new NullProgressMonitor());
647 dynamicPage.performDefaults();
648 } catch (CoreException e) {
649 CUIPlugin.log(Messages.ErrorParsTab_error_OnApplyingSettings, e);