Using StyledCellLabelProvider in a TableViewer killed my tooltips - eclipse-plugin

I have a TableViewer in my Eclipse plugin.
When I was just using a regular label provider, my tooltips worked beautifully:
However, when I switched to have my LabelProvider implement IStyledLabelProvider, my tooltips went haywire:
Here is the code creating the StyledString
#Override
public StyledString getStyledText(final Object element) {
if( !(element instanceof MyInterface<?>) ) {
return null;
}
final String elemText = getColumnText(element, this.columnIndex);
final StyledString styledString = new StyledString(elemText == null ? "" : elemText);
if( !(element instanceof MyObject) ) {
return styledString;
}
final MyObject settingElement = (MyObject) element;
// grayed out text
if( settingElement.shouldBeGray() ) {
styledString.setStyle(0, elemText.length(), AdaptabilityStyles.GRAY_STYLER;
} else if( !settingElement.shouldBeBlue() ) {
styledString.setStyle(0, elemText.length(), AdaptabilityStyles.BLUE_STYLER);
}
return styledString;
}
And getTooltTipText()
#Override
public String getToolTipText(final Object element) {
return getColumnText(element, this.columnIndex);
}
What am I doing wrong?

As I was writing this question, I wanted to reference a bug report that I am familiar with that is related to tooltips. I looked at the bug report again and came across the following line:
For now, I simply try this :
ColumnViewerToolTipSupport.enableFor(commonViewer)
I wasn't calling that method when I created my viewer. When I tried that, my tooltips came back (though slightly different than they were before.

Related

How to get similar behaviour as the Java browsing perspective with two commonNavigator views?

I'd like to reproduce the behavior of the Java browsing perspective as so : the user select a file (selectedFile) from a Custom Common Navigator View (VariabilityNavigator) and it displays only the related files to that selection in another Custom Common Navigator View (ConfigFileNavigator). It refreshes automatically as the selection goes.
I use Common navigator because I want to display the package of the related files and not the other ones or the empty ones. That I coded fine.
Could you please walk me thru the steps to do that ? Here is how far I got..
I have successfully coded the first view VariabilityNavigator.
I thought I would use a filter ConfigurationFilesFilter to get the selectedFile and use it to filter the related files.
I can get the selection from the VariabilityNavigator within the select(...) of ConfigurationFilesFilter code below
I then use it to filter the files I want to display using isRelatedToSelection. I haven't write that part yet, but it's not a problem for testing.
This method don't work for several reasons : it doesn't refresh and I have to click on the ConfigFileNavigator to get the result. What it should do : when I click on the first view and it should automatically display the result in the second view. Thanks for your help.
public class ConfigurationFilesFilter extends ViewerFilter {
String selectedFile;
public ConfigurationFilesFilter() {
}
#Override
public boolean select(Viewer viewer, Object parent, Object element) {
selectedFile = getVariabilityNavigatorSelection();
if (isChildElement(element)) {
return handleChild(element);
} else {
// manipulate tree viewer based on select decision for the sub elements
StructuredViewer sviewer = (StructuredViewer) viewer;
ITreeContentProvider provider = (ITreeContentProvider) sviewer.getContentProvider();
for (Object child : provider.getChildren(element)) {
if (select(viewer, element, child)) {
return true;
}
}
return false;
}
}
/**
*
* #param element
* #return true to be displayed
*/
private boolean handleChild(Object element) {
return true;
}
/**
* Check if an element is a java file and if it is related to the selection
*
* #param element
* #return boolean
*/
private boolean isChildElement(Object element) {
if (element instanceof IFile) {
if (((IFile) element).getFileExtension().equals("java")) {
return (isRelatedToSelection((IFile) element));
}
return false;
}
return false;
}
public String getVariabilityNavigatorSelection() {
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
IViewPart viewPart = page.findView(VariabilityNavigator.ID);
String VariabilityNavigatorSelection = "" ;
if (viewPart == null) {
VariabilityNavigatorSelection = "open Variability view. \r\nTo do so, open the menu as followed:\r\nWindow > Show view > Other... > SPL > Variability Navigator";
} else {
ISelectionProvider selProvider = viewPart.getSite().getSelectionProvider();
IStructuredSelection sel = (IStructuredSelection) selProvider.getSelection();
if (sel.isEmpty()) {
VariabilityNavigatorSelection = "selection vide";
}
Iterator<?> i = sel.iterator();
while (i.hasNext()) {
final Object o = i.next();
if (o instanceof IFile) {
VariabilityNavigatorSelection = ((IFile) o).getName();
} else
VariabilityNavigatorSelection = "Please select a file";
}
}
if (!VariabilityNavigatorSelection.isEmpty())
printTrace("selectPrint = " + VariabilityNavigatorSelection);
return VariabilityNavigatorSelection;
}

How to display a Labels 'Error on ErrorProvider1'

Goal
I want to display the text that I put in the Label's "Error on ErrorProvider1" attribute whenever I get an error. See the following label's attributes below.
I try to display the text in the red rectangle into my ErrorProvider1 SetError(control, value) function.
If TextBox1.Text.Trim.Contains("'") Then
ErrorProvider1.SetError(lblErr, ErrorProvider1.GetError(lblErr))
Else
ErrorProvider1.SetError(lblErr, "")
End If
How can I retrieve the 'Error on ErrorProvider1' text from the lblErr to display it in the ErrorProvider1 SetError value?
The ErrorProvider component is very awkward to use effectively. It is fixable however, I'll give an example in C# that extends the component with some new capabilities:
ShowError(Control ctl, bool enable) displays the text that you entered at design-time when the enable argument is true. The easier-to-use version of SetError().
HasErrors returns true if the any active warning icons are displayed. Handy in your OK button's Click event handler.
FocusError() sets the focus to the first control that has a warning icon, if any. It returns false if no warnings are remaining.
SetError() is a replacement of ErrorProvider.SetError(). You only need it if you add any controls after the form's Load event fired or if you need to modify the warning text.
Add a new class to your project and paste the code shown below. Compile. Drop it from the top of the toolbox onto the form. The design-time behavior is identical. Modestly tested.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.ComponentModel.Design;
class MyErrorProvider : ErrorProvider {
public void ShowError(Control ctl, bool enable) {
// Easy to use version of SetError(), uses design-time text
if (!enable) base.SetError(ctl, "");
else {
if (errors.ContainsKey(ctl)) base.SetError(ctl, errors[ctl]);
else base.SetError(ctl, "No error text available");
}
}
public bool HasErrors {
// True if any errors are present
get {
foreach (var err in errors)
if (!string.IsNullOrEmpty(base.GetError(err.Key))) return true;
return false;
}
}
public bool FocusError() {
// Set the focus to the first control with an active error
foreach (var err in errors) {
if (!string.IsNullOrEmpty(base.GetError(err.Key))) {
err.Key.Focus();
return true;
}
}
return false;
}
public new void SetError(Control ctl, string text) {
// Use this only to add/modify error text after the form's Load event
if (!string.IsNullOrEmpty(text)) {
if (errors.ContainsKey(ctl)) errors[ctl] = text;
else errors.Add(ctl, text);
}
base.SetError(ctl, text);
}
private void initialize(object sender, EventArgs e) {
// Preserve error text
copyErrors(((Form)sender).Controls);
}
private void copyErrors(Control.ControlCollection ctls) {
foreach (Control ctl in ctls) {
var text = this.GetError(ctl);
if (!string.IsNullOrEmpty(text)) {
errors.Add(ctl, text);
base.SetError(ctl, "");
}
copyErrors(ctl.Controls);
}
}
private Dictionary<Control, string> errors = new Dictionary<Control, string>();
// Plumbing to hook the form's Load event
[Browsable(false)]
public new ContainerControl ContainerControl {
get { return base.ContainerControl; }
set {
if (base.ContainerControl == null) {
var form = value.FindForm();
if (form != null) form.Load += initialize;
}
base.ContainerControl = value;
}
}
public override ISite Site {
set {
// Runs at design time, ensures designer initializes ContainerControl
base.Site = value;
if (value == null) return;
IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (service == null) return;
IComponent rootComponent = service.RootComponent;
this.ContainerControl = rootComponent as ContainerControl;
}
}
}
Your issue is that you are replacing the error message when nothing is wrong. As noted in your comment below, you are storing the localized error message in the label's Tag, so you can do the following:
If TextBox1.Text.Trim.Contains("'") Then
ErrorProvider1.SetError(lblErr, lblErr.Tag)
Else
ErrorProvider1.SetError(lblErr, "")
End If
You were correct to use ErrorProvider1.GetError(Control) to get the value. It's just that you're more than likely replacing it with an empty string before you were retrieving it.

How to get the project when right-click on a project/file/others in an eclipse-plugin

I'm write a simple eclipse plugin, but have a problem: When user right-click on a node(maybe a project, a file, a java compilation unit, or others), I want to get the project it belongs.
The sample code is:
public class MyAction implements IObjectActionDelegate {
private IProject project;
public void selectionChanged(IAction action, ISelection selection) {
this.project = getSelectedProject(selection);
}
public static IProject getSelectedProject(Object obj) throws Exception {
if (obj == null) {
return null;
}
if (obj instanceof IResource) {
return ((IResource) obj).getProject();
} else if (obj instanceof IStructuredSelection) {
return getSelectedProject(((IStructuredSelection) obj).getFirstElement());
}
return null;
}
}
It works at most of time, but sometimes, for example, I right-clicked on a java file, the selection will be a ICompilationUnit. Although I can add one more if in the getSelectedProject, but I don't think it's a good idea.
Is there a way to get the project of selected objects nomatter what have been selected? I don't want to add them one by one.
ICompilationUnit extends IAdaptable (see http://publib.boulder.ibm.com/infocenter/rsmhelp/v7r0m0/index.jsp?topic=/org.eclipse.jdt.doc.isv/reference/api/org/eclipse/jdt/core/ICompilationUnit.html)
You can try and use the IAdaptable interface like that:
if (obj instanceof IAdaptable) {
IResource res = (IResource)(((IAdaptable)obj).getAdapter(IResource.class));
if (res != null) {
return res.getProject();
}
}
There are no way to convert an ICompilationUnit, IPackage, or whatever, to an IResource as there are most often no corresponding resource! E.g. for the .class elements in the navigator, the element corresponds to an entry in a JAR file or in a dependency plug-in from the target platform.
it up answer don't work, may it should be:
if (obj instanceof IStructuredSelection) {
IStructuredSelection selection1 = (IStructuredSelection)obj;
Object element = selection1.getFirstElement();
IProject project = null;
if (element instanceof IProject) {
project = (IProject) element;
} else if (element instanceof IAdaptable) {
project = (IProject) ((IAdaptable) element).getAdapter(IProject.class);
}
if (project != null) {
return project;
}
}

Eclipse Plugin Development : How to change file attributes of selected files?

I am trying to create an eclipse plugin to change the selected files to read only. Created popup menu sample plugin project which when executed shows a message "New Action was executed"
I am stuck at next step.
How to get list of files selected, and change file attributes ?
I don't have the time to test the following properly, but it is probably a good starting point:
public class SetFileToROHandler extends AbstractHandler implements IHandler {
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
final ISelection s = HandlerUtil.getCurrentSelectionChecked(event);
if (!(s instanceof IStructuredSelection))
return null;
final IStructuredSelection ss = (IStructuredSelection) s;
for (final Object o : ss.toArray()) {
if (!(o instanceof IFile)) {
continue;
}
IFile f = (IFile) o;
f.setReadOnly(true);
}
return null;
}
}

MVVM-Light and WP7 ViewModel tombstoning isn't working

I've tried following the steps in Joost Van Schaik's article on tombstoning but was unable to get it to work for me. I'm no doubt doing something wrong. In my ViewModel:
private string _foobar ="init";
public string testStr
{
get
{
return _foobar;
}
set
{
_foobar = value;
}
}
And in my page:
<TextBox x:Name="tBoxTest" Text="{Binding testStr, Mode=TwoWay}" />
While the application is running, changing the value in tBoxTest sets _foobar just fine, but try to serialize it and it’s as if it has forgotten the instance??? Any help would be greatly appreciated.
I was able to get tombstoning to work, along with having an object be visible to all my ViewModels, by doing the following:
In a Model class, I added:
private static Model1 _instance;
public static Model1 Instance
{
get { return _instance; }
set { _instance = value; }
}
public static void CreateNew()
{
if (_instance == null)
{
_instance = new Model1();
_instance.FirstString = "init";
}
}
Then in ApplicationExtensions.cs I added:
public static void SaveToIsolatedStorage(this Application app, Model1 model)
{
var dataFileName = GetIsFile((model.GetType()));
using (var userAppStore =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (userAppStore.FileExists(dataFileName))
{
userAppStore.DeleteFile(dataFileName);
}
using (var iss = userAppStore.CreateFile(dataFileName))
{
SilverlightSerializer.Serialize(model, iss);
}
}
}
And in App.xaml.cs I changed LoadModel() to:
private void LoadModel()
{
try
{
Model1.Instance = this.RetrieveFromIsolatedStorage<Model1>();
}
catch (Exception) { }
if (Model1.Instance == null) Model1.CreateNew();
}
That all made things like this work in my ViewModel files:
public string TestStr
{
get
{
return Model1.Instance.FirstString;
}
set
{
Model1.Instance.FirstString = value;
}
}
And by that, I mean that the Model1 object is getting serialized and tombstoning is working - at least I’m getting what I think I want. I’ve tested it a lot by navigating between apps, phone settings, turning the phone off and on, locking it and calling it while in the app from another phone. Performance when deserializing is great. And I can work with the vars.
That said, Mr. Van Schaik replied to a request for assistance with: "If you are subclassing from an MVVMLight ViewModelBase it does, and then you should call RaisePropertyChanged from your setter like this:
private string _foobar ="init";
public string TestStr
{
get
{
return _foobar;
}
set
{
RaisePropertyChanged("TestStr");
_foobar = value;
}
}
RaisePropertyChanged notifies any listenings views (i.e. the TextBox you bound to it) that a property is changed and that the should update their contents. This is a crucial mechanism."
So I will work with what I was originally trying but with the addition of RaisePropertyChanged to see what that does.
UPDATE
Although I implemented RaisedPropertyChanged (using the code snippet mvvminpc) in my MainViewModel.cs file, that still had no effect (as good as it may be for other things) on serializing anything created within the ViewModel. I'm probably still doing something wrong, but it may also be because view models inherit from a protected class (answer from Laurent Bugnion). I (very reluctantly) tried changing that class from protected to public and recompiling, but it didn't help in my case and I hate to fork a referenced library like that. Anyway, I'm just forging ahead for now with creating the Model1 instance in App.xaml.cs. Seems to work. While I was at it, I modified one of Van Schaik's methods to accept any type of object:
public static void SaveToIsolatedStorage<T>(this Application app, T obj)
where T : class
{
var dataFileName = GetIsFile(typeof(T));
using (var userAppStore =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (userAppStore.FileExists(dataFileName))
{
userAppStore.DeleteFile(dataFileName);
}
using (var iss = userAppStore.CreateFile(dataFileName))
{
SilverlightSerializer.Serialize(obj, iss);
}
}
}
From the code you've posted there isn't an instant answer.
My advice to debug this is:
if you've copied the code exactly from that article then add something (a messagebox?) to the empty catch handler - `catch (Exception){ }
use the debugger to put breakpoints in the LoadModel and SaveToIsolatedStorage methods
use these breakpoints to step through the Load and Save code - is the code correctly loading and saving?
To be honest, with problems like this, doing a little investigation yourself is much better than asking questions on here (IMO!)