Is there an example out there for using IDecorationContext for label decorations?
By the looks of it, IDecorationContext class seems to provide some sort of contextual decoration support, but for the life of me, I can not find any sample code using this feature...
Has anybody actually used decoration context feature and if so, what use cases did it solve?
PS: I am looking for a way to apply image decorations to object labels and depending on where the object is displayed, the base icon size varies (e.g. traditional "small" icons in table- and tree items and larger icons for content headers).
The decorations applied to the original icons should choose appropriate size decorations accordingly.
IDecorationContext seems to fit the bill for what I need it for, but the documentation is as sparse as one can expect from a minor feature of an open source library and there are no examples to be found.
Googling for the "IDecorationContext" did not reveal anything interesting either, so I turn to StackOverflow crowd wisdom in hopes next guy getting the question would be able to get their answer faster ;)
I did not use IDecorationContext, but you can see it used in org.eclipse.jface.viewers.LabelDecorator.
It is also discussed in this thread (even if there are no answer, that can at least give you a starting point)
My current approach is to extend org.eclipse.ui.decorators using a
ILightweightLabelDecorator to add a replace overlay to the respective
icons:
public class ProjectLabelDecorator extends LabelProvider
implements ILightweightLabelDecorator {
...
public void decorate(Object element, IDecoration decoration) {
if (element instanceof IFolder) {
IFolder folder = (IFolder) element;
try {
if (folder.getProject().hasNature("rttdt.nature")) {
if (ProjectNature.isTestcase(folder)) {
IDecorationContext context =
decoration.getDecorationContext();
if (context instanceof DecorationContext) {
((DecorationContext) context).putProperty(
IDecoration.ENABLE_REPLACE, Boolean.TRUE);
}
decoration.addOverlay(fTestcaseOverlay,
IDecoration.REPLACE);
}
} catch (CoreException e) {
}
}
}
...
}
Related
I am working on a java swing application using synth Look and Feel.
There are already styles for every possible swing component
I must change the whole application's LookAndFeel, redefining different styles for every possible swing component.
I am now working on a sandbox, launched outside of the application. The sandbox loads my new set of styles, while the application still loads the old ones. No problems for now
However, I must then integrate it 'progressively' in the application. Meaning that in the same java application, some HMIs must use the old set of styles, while some must use the new ones
The difficulty being that each set of styles define synth "region" styles that automatically apply to the corresponding component, and I don't know how deal with several region styles that correspond to the same component type
Anybody has an idea of how I can do this ?
I saw that in swing's UIManager, one can change the LookAndFeel, but it then changes for the whole application
Only workaround I saw on the internet was to change the LookAndFeel before instanciating a Component, then change it back, which looks like an awful solution
Thanks in advance
Only workaround I saw on the internet was to change the LookAndFeel before instanciating a Component, then change it back, which looks like an awful solution
This is a very very very x 10 times bad solution.
I'm the author of the material-ui-swing and with the material style, you need to work with this concept of different style, and this is the main focus that I had during my development with the library, also because at the same time we integrate the library in one of the famous swing application called JMars where we need to respect a design system given by the UX team.
To make an example, material-ui-swing give two types of API:
one it the Material Theme System to define in a declarative way the theme around the App, and
the second is to give the lower-level API to implement the UI component with a different style.
In your case, we need the second power of material-ui-swing which is the lower-level API, and I will add an example also reported inside the repository online at the following link, and the complete doc is available here
A possible example of customization is the following on
public class ContainedButtonUI extends MaterialButtonUI {
//The propriety order inside the method installUI is important
//because some propriety should be override
#Override
public void installUI(JComponent c) {
super.mouseHoverEnabled = false;
super.installUI(c);
super.mouseHoverEnabled = true;
super.colorMouseHoverNormalButton = MaterialColors.PURPLE_500;
super.background = MaterialColors.PURPLE_700;
c.setBackground(super.background);
if(super.mouseHoverEnabled){
c.addMouseListener(
MaterialUIMovement.getMovement(c, this.colorMouseHoverNormalButton)
);
}
//If you want use this style also for Default button
// super.defaultBackground = MaterialColors.PURPLE_700;
//super.colorMouseHoverDefaultButton = MaterialColors.PURPLE_500;
super.borderEnabled = false;
}
After that to keep all your app architecture clean you can add the following specialization of JButton
/** #author https://github.com/vincenzopalazzo */
public class ContainedButton extends JButton {
public ContainedButton() {}
public ContainedButton(Icon icon) {
super(icon);
}
public ContainedButton(String text) {
super(text);
}
public ContainedButton(Action a) {
super(a);
}
public ContainedButton(String text, Icon icon) {
super(text, icon);
}
#Override
protected void init(String text, Icon icon) {
super.init(text, icon);
// When you don't want anymore you just delete the
// following line
setUI(new ContainedButtonUI());
}
Of curse, maybe the library can not help you in all your component styles, but nobody said that the library can not evolve with the help of the community.
A not complete description of components can be found here
Thank you all for your answers and sorry for my lack of reactivity during the holidays
I think I found a solution, which is not exactly what I asked for but answers my problem :
I will not make several LookAndFeels coexist.
Instead, I will load all styles, new and old, in the same LookAndFeel, and use different setName() for new and old components
For region styles (which was the problematic here), I will make a custom SynthStyleFactory which will redirect to the correct region style
Once all HMIs are migrated, I will delete the old styles and the custom factory which won't be needed anymore
When we are creating a component, this component takes some initial values and it will be styled accordingly to the active Look & Feel. For example, a JButton will start with horizontal alignment equals to 0 (probably SwingConstants.CENTER).
My question is, are these look and feels able to "change-override" these initial values of the default components (I am not talking for NimbusButton extends JButton). Again, I'm referring only to this kind of properties all components have, and not styles and how they look (even if some of these properties affect the appearance of the component).
I have tested the previous value (JButton.horizontalAlignment) with Java's look and feel, my system's look and feel (Windows 10) and Nimbus. The value seems to remain the same. But what about other LAFs, or other values from other Components?
One could say, that my question can be experessed also as "What look and feels are able to change"?
public class LookAndFeels {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// No look and feel
System.out.println(new JButton().getHorizontalAlignment());
// Nimbus
setNimbusLAF();
System.out.println(new JButton().getHorizontalAlignment());
setSystemLAF();
System.out.println(new JButton().getHorizontalAlignment());
});
}
private static void setSystemLAF() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
private static void setNimbusLAF() {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
this question can't have a full answer (trust me when i say it's too complicated ,I'm implementing one from scratch and it's 4 month now and i don't even know if I'm close to call it!) .
My question is, are these look and feels able to "change-override" these initial values of the default components
yes and no,they can change such properties but it's them responsibility to honor'em .
plus most of the initial values are first to show-up look and feel values, here this will give you a hint about what happend at your first println
the real answer will be checking the ComponentUI implementation of the one you are asking about .
you are a coder so it's not a shock for you to find out what they can change is the same as any code out side of it's original package (since code is code!!).
I have tested the previous value (JButton.horizontalAlignment) with Java's look and feel, my system's look and feel (Windows 10) and Nimbus. The value seems to remain the same. But what about other L&F's, or other values from other Components?
every ui object have a method called installUI(JComponent c) this question answer is wrapped around this method , this method is called when you change the ui and depending on the implementation their ,they change some of the properties to fit them need's (E.g take any of the dark L&F's as an example ,them implementation for AbstractButton ui will have to set the background to a dark color and the foreground to bright color so the text would appear since they are dark ).
"What look and feels are able to change"
many people think that the ui control a small bits of the component , but in real it's all from the ui !! for instance AbstractButton have text , many people think that the ui is not responsible to display it but it's other way around !, if the ui didn't call Graphics.drawString(AbstractButton.getText(),x,y) (or something equivalent) somewhere in their paint(Graphics g,JComponent c) method no text will be
so the short answer to your question 'every thing on the screen' .
Mathematica comes with a simple java program that allows to inspect the communication between front end and the kernel. It's called LinkSnooper and in general it works quite nice. It looks like this
I think I can improve the behavior and usability of the program to some extend, but to do this, I need to reimplement some parts. One fundamental piece that I need is a text pane, which has the following properties:
it can receive a lot of data and it probably should use a fast ring-buffer so that the very first log-lines are removed when the data grows too much. Another possibility is that it automatically starts to write data to disk and possibly reloads it when the user scrolls up to see the first entries
it should be able to handle colored text. I plan to use a simple highlighter (the log-data is actually real Mathematica syntax) on each arriving line to make reading more easy
it doesn't need to be writable. It's OK if the text pane is read-only.
Question: Does something like this already exist? Currently, LinkSnooper uses a JTextArea underneath and before I start do write my own version, I wanted to ask whether someone has already done this.
Edit:
What I planned to do was to use some Logger framework because it seems natural to me that those libraries should be able to handle a lot of data. Additionally, they often provide interfaces to format the messages and you can define different handlers that can take care of different messages. What I was hoping for was that someone already has combined this with a neatly working text window that can handle large output.
As Simon has pointed out I would suggest using JavaFX for this task.
If you "just" need to display large amounts of log data without advanced highlighting (sub-string range highlighting), ListView is the component for you.
It uses a virtualized layout container, so only the cells that are in the visible area of the viewport are actually rendered. This allows for lazy loading, cell recycling etc.
The ListView uses an ObservableList as its DataStructure. Similar to EMF EList, the ObservableListautomatically notifies the ListView on changes in its contained data.
There are several factory methods to create an ObservableList via FXCollections even allowing to wrap an existing List (e.g. RingBuffer).
If you need the advanced highlighting, RichTextFX is probably the solution to go for as it allows detailed styling of its contained text. RichTextFX uses a virtualized layout, too.
Edit #2
Tom has written about this in his blog: http://tomsondev.bestsolution.at/2014/12/27/displaying-and-editing-large-styled-texts/
Edit #1 ListView example
JavaFX does a very good job at separating the model from the view, so we try not to mix this up and need to create two things:
A data class (model)
A Cell renderer for that data class (view).
First the data class:
public class LogData {
private final String logMessage;
private List<String> highlightedFragments = null;
public LogData(String pLogMessage) {
logMessage = pLogMessage;
}
public String getLogMessage() {
return logMessage;
}
public List<String> getHighlightedFragments() {
if (highlightedFragments == null) {
doHighlight();
}
return highlightedFragments;
}
private void doHighlight() {
List<String> highlightedParts = Collections.emptyList(); // TODO lexer
highlightedFragments = highlightedParts;
}
}
The interesting part is, that the highlighting is done on demand not on initialization. Or in other words: The lexer only performs its work, when the cell renderer requests the data.
Now the Cell renderer:
ListView<LogData> listView = new ListView<>();
listView.setCellFactory(cb -> new LogDataCell(){});
public class LogDataCell extends ListCell<LogData>
{
#Override
protected void updateItem(LogData item, boolean empty) {
super.updateItem(item, empty);
if(empty || item == null) {
setText(null);
setGraphic(null);
}
else {
List<String> fragments = item.getHighlightedFragments();
if(fragments == null || fragments.isEmpty()) {
setText(item.getLogMessage());
setGraphic(null);
}
else {
TextFlow textFlow = null; //TODO
setText(null);
setGraphic(textFlow);
}
}
}
}
This is not a fully working example, there are several TODOs left, but hopefully you get the idea.
If you want to add search highlighting, I described a similar approach for the TableView control element here: JavaFX Table with highlighted text (Labels) with poor performance
I am not skilled in GUI design. After much thought, research and experimentation I've developed several design ideas but still none that seems efficient. One design has a Session god object register a listener on every UI element when created, and every object that cares about any action registers a listener on the Session object. This seems simple and robust, as all messaging goes through a central location so it's less likely that anything is lost. It's brute force though, and seems cumbersome and inefficient.
Another design attempts to create subgroups of objects that speak to each other. This avoids the huge top-level Session and seems more efficient, but also seems error prone.
I'm trying to implement a framework for reuse where I group buttons with related purposes into toolbars and have a hierarchical approach to listening for actions performed by toolbars with relevant operations to the listener. I've gotten to this so far:
public class EditorToolBar extends JToolBar {
public static enum Command {
ZOOMIN,
ZOOMOUT,
FINER,
COARSER,
RESET
}
private ButtonCommandListener listener = new ButtonCommandListener();
public EditorToolBar() {
super("Editor Commands");
JButton button;
for (final Command cmd : Command.values()) {
button = new JButton(cmd.toString());
button.setEnabled(true);
button.setToolTipText(cmd.toString() + " Command");
button.setActionCommand(cmd.toString());
button.addActionListener(listener);
add(button);
}
}
public void addActionListener(ActionListener pNewListener) {
listener.cActionNotifier.addListener(pNewListener);
}
private class ButtonCommandListener implements ActionListener {
private NotifierImp<ActionListener> cActionNotifier = new NotifierImp<ActionListener>();
public void actionPerformed(ActionEvent pEvent) {
for (ActionListener listener : cActionNotifier) {
listener.actionPerformed(pEvent);
}
}
}
} // class EditorTooBar
and the listeners implement something like this:
public void actionPerformed(ActionEvent pEvent) {
switch (EditorToolBar.Command.valueOf(pEvent.getActionCommand())) {
case ZOOMIN:
// do something
break;
case ZOOMOUT:
// do something
break;
case FINER:
// do something
break;
case COARSER:
// do something
break;
case RESET:
// do something
break;
default:
System.out.println("Unknown EditorToolBar Command: "+pEvent.getActionCommand());
return;
}
I can enhance the instructor for the enum to also include tooltip text, images, etc. I'd like to reuse this design with just a different enum describing other toolbars. Listeners will distinguish different button actions using ActionEvent.getActionCommand() and use Command.toValue(String). I'd like this to extend to a hierarchy of classes that are listening: a superclass may implement a listener for one type of toolbar, and subclass add to that by listening for a different toolbar type. If the event is not from the toolbar the subclass is interested in, it can forward the event to the superclass. To make this work, I need a way to distinguish between one toolbar and another, but preferably without having to check for every button event possible from that toolbar. Ideally I'd like to have a toolbar factory, and just specifying an enum would be enough to fully describe a toolbar. Not being able to subclass an enum adds to the challenge here.
Is this a promising design pattern to pursue? I've not seen it anywhere else yet. Is there a better way that I should be using rather than inventing something that is inferior? A link to other options would be welcome.
Edit: Based on the answer from yash ahuja I should clarify that when I mention hierarchy I mean similar to the way that key bindings are handled (i.e. do you have a binding? No, then does your container have a binding? ... until someone consumes the key event) not the actual class hierarchy.
As a way to encapsulate functionality, consider combining JToolBar, discussed in How to Use Tool Bars, with Action, discussed in How to Use Actions. The example cited here exports a single tool bar. In contrast, the StyledEditorKit, illustrated here, exports families of Action subtypes that apply to the current selection of a text component.
The design is pretty good but if you create a hierarchy of Tool bars then, in a situation where a particular button is clicked on particular tool bar the corresponding action performed for that button may not be accurate. Also at times multiple events can be triggered.
Also there are some tool bars for which it is difficult to identify that under which super class they should belong or if they are implementing features from multiple tool bars you need multiple inheritance which Java does not supports.
Possibly a combination of Strategy Pattern and Factory Pattern could solve these issues. Please rethink on this and design your solution, sorry I don't have exact design or source for your question , I have just put my thoughts for your solution.
Regards,
Yash
I am developing a GWT app (I'm fairly new to GWT so this is a request for best practices; I haven't found any relevant answer on SO or elsewhere) where a timeline is required. This timeline (with descriptions, labels, interaction handles, and plots) resides in its own container (a Panel).
[<] [now] [>] // Interaction (navigation)
2007 2008 2009 2010 // Labels
| | | |
+ Group 1 // Collapsible groups
- Group 2
Item 2a ===== == // Item with plots (plots are wrapped in container per Item)
Item 2b ===== === =
-Group 3
Item 3a ===
Item 3b ===
Now, when user's navigate the timeline (using the button to move forward or backwards), I need to recalculate some elements of the layout:
Labels need recalculating / repositioning
Plots need recalculating / repositioning. Plots are based on a set of Timeslot elements (extends Widget, attributes dateStart and dateEnd) which are already related to Items which are related to Groups.
The collapsible panels are DisclosurePanels.
As far as I can tell, I now have two options for handling navigation:
I can clear() the container panel and do a complete redraw. For this, I need to preserve the state (collapsed/expanded) for all groups. (Groups and items are static for the entire period, by the way!) This will give one big redraw.
I can let the plot containers (each Item has its own TimeslotContainer which is a FlowPanel) hold a reference to all its Timeslots and then let every TimeslotContainer redraw itself (i.e., filter and position relevant Timeslots) based on the current timespan. This will give several minor redraws (one per Item per expanded Group), the advantage being that the DisclosurePanels will be preserved, thus maintaining their own state.
I'm inclined to go with the second solution. But are there any best practices on this one? Am I missing some common gotchas?
If groups and items are static I would also recommend the second approach.
DOM operations (constructing, etc) are properly the most expensive functions in a GWT application (performance wise) so these DOM operations should be kept at a minimum.
However I don't think performance may be a big issue here because the amount of DOM elements is relatively low.
Nevertheless I still think the second approach is better. You don't have to store the state for groups and items and as they are static it doesn't really make sense to redraw them.
I can only think of one advantage of the first approach:
There will be only one relatively easy draw function. In the second approach all TimesSlotContainer have to implement a function in order to redraw themselves and also take into account position and context of the Timespan. That function might be more complicated then one big re-draw function.
I went ahead and implemented a version of the second solution under the original intention to try the first if the second did not perform sufficiently. (This was never realized, though, as the second solution performed highly satisfactorily.)
What I asked in the question was primarily references to the GWT way to do this. I still haven't found anything written regarding this issue and so suspect that nobody has missed such guidelines before :) To conclude my search, I will self-answer the question outlining the way I ended up implementing together with the (assumed) pros and cons. Thanks to #Ümit for supporting my instincts. The following is in part intended to address the last paragraph in #Ümit's answer regarding the complexity of the draw methods.
I ended up letting TimeslotContainers (the Panels containing TimeSlots), LabelPanel (Panel with generated HTML elements), and NavigationPanel realize a simple interface:
public interface IReceivesPeriodChangedEvents {
public void periodChanged();
}
A simple EventBus handled the notification process on these IReceivesPeriodChangedEvents instances:
public class EventBus {
private static EventBus instance;
private Set<IReceivesPeriodChangedEvents> receivers;
private EventBus() {
this.receivers = new HashSet<IReceivesPeriodChangedEvents>();
}
public static EventBus getInstance() {
if (instance == null) {
instance = new EventBus();
}
return instance;
}
public void addReceiver(IReceivesPeriodChangedEvents receiver) {
this.receivers.add(receiver);
}
public void notifyPeriodChanged() {
for (IReceivesPeriodChangedEvents receiver : this.receivers) {
receiver.periodChanged();
}
}
}
Whenever one of TimeslotContainer, LabelPanel or NavigationPanel were instantiated (once per page load, these objects are reused throughout the lifetime of the page) they made sure to subscribe to the EventBus:
public class TimeslotContainer extends FlowPanel implements IReceivesPeriodChangedEvents {
public TimeslotContainer(/* ... */) {
// ...
EventBus.getInstance().addReceiver(this);
}
// ...
}
In order to handle the "complex" draw method, I simply created a method (buildFromStore()) to add relevant Widgets (e.g., newly created Timeslot objects on the TimeslotContainers). This resulted in great reuse of the draw method:
public class NavigationPanel extends FlowPanel implements IReceivesPeriodChangedEvents {
public NavigationPanel() {
// ...
buildFromStore();
EventBus.getInstance().addReceiver(this);
}
private void buildFromStore() {
// Add lots of HTML elements here
}
#Override
public void periodChanged() {
clear();
buildFromStore();
}
}
Simple as that!
In conclusion:
No gotchas encounted. Lots of minor redraws did not seem to be a problem (I never implemented solution one, though). The draw methods could be reused (in this case, at least). The collapsible DisclosurePanels never lost their state as they were never replaced (only their contents were).