I'm working a plugin that generates method within a class.
The problem is that the code I generate gets inserted randomly between other fields and methods. EG. I have 4 fields and my method gets inserted between the second and the third field breaking the field section in two parts.
Question: How to insert the new code after fields section?
Here is the code I'm using:
MyMembersHandlerBase extends GenerateMembersHandlerBase {
#Override
protected List<? extends GenerationInfo> generateMemberPrototypes(
PsiClass psiClass, ClassMember[] members) {
PsiMethod method1 = // method generation logic
PsiMethod method2 = // ...
return asList(
new PsiGenerationInfo(method1),
new PsiGenerationInfo(method2),
...
);
}
#Override
protected ClassMember[] getAllOriginalMembers(PsiClass psiClass) {
// ...
}
}
Update: I've found "Rearrange Code" feature in UI. Probably invoking it programmatically would solve my problem, but I haven't found so far how to do that.
The action can be called this way:
Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
ActionManager actionManager = ActionManager.getInstance();
AnAction rearrangeAction = actionManager.getAction("RearrangeCode");
DataContext dataContext = DataManager.getInstance()
.getDataContext(editor.getContentComponent());
Presentation presentation = rearrangeAction.getTemplatePresentation();
rearrangeAction.actionPerformed(
AnActionEvent.createFromDataContext("", presentation, dataContext)
);
But IMHO more correct is to search AST for first method or end of declaration and insert method in right place.
Related
I use Vaadin 14 and would know whether it is possible to report changes in the nested list to objects in the main view.
A rough example is shown in the picture. Above you can see the sum as size (here 2), if I press Delete it should change to 1.
Is that possible and how?
concept
I don't have any code yet, it's a thought where I would like to have a hint about what would be possible, e.g. Observer Pattern or something, but code could look something like this
code:
#Rout("")
public class MainView extends VerticalLayout {
private List<CustomDetails> customDetails = new ArrayList<>();
public MainView(){
final var form = new FormLayout();
customDetails.forEach(form::add);
add(H1("Header"), form)
}
}
public class CustomDetails extends Details{
private CustomForm customForm;
private final Service service;
public CustomDetails(){
customForms = new CustomForm(service.getListOfObjects());
this.setContent(customForms)
}
}
public class CustomForm extend FormLayout{
private FormLayout formLayout = new FormLayout();
private List<Object> objects = new LinkedList<>();
public CustomForm(List<Object> list){
this.objects = list;
setUp();
add(new Paragraph("SUM: "+ list.size()), layout);
}
private void setUp(){
objects.forEarch(o->{
....
layout.add(...)
})
}
}
In Vaadin there is an utility class Binder which is used to bind data to forms. If your use case is related to this, i.e. your so called nested layout is in fact a form and objects you refer to are data beans you want bind into that form. I recommend to study that first.
If you have list editor, I would also investigate if it fits your application to implement it with Grid or IronList/VirtualList, which is backed by DataProvider. Say you edit one item, and after saving the item, you can call dataProvider.refreshItem(item) to update the view.
Observer Pattern or something...
Yes, that is a solution. It is a lot of work and has been done before.
One such library is Beanbag.
Note: I wrote this (or rather, I started writing it a day ago).
EDIT:
As of this edit, we have the ObservableCollection interface. You can use it like so:
// You have a collection called "strings".
// Wrap it in an ObservableCollection.
final ObservableCollection<String, Collection<String>, BasicObservableCollection.Default<String, Collection<String>>> observableStrings = ObservableCollections.observableCollection(strings);
// Add a removed observer.
observableStrings.addElementRemovedObserver(observation -> System.out.println("\"" + observation.getValue() + "\" was removed.");
// Remove an element.
observableStrings.remove("hello");
If you need the wrapper to have List methods, just wait until tomorrow evening EST. I'll have the code up by then and will update this post accordingly.
I am trying to extract the calls from the method run() to the constructors. Here is the code I am trying to parse
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Create the two text areas
TextAreaFigure ta = new TextAreaFigure();
ta.setBounds(new Point2D.Double(10,10),new Point2D.Double(100,100));
TextAreaFigure tb = new TextAreaFigure();
tb.setBounds(new Point2D.Double(210,110),new Point2D.Double(300,200));
// Create an elbow connection
ConnectionFigure cf = new LineConnectionFigure();
cf.setLiner(new ElbowLiner());
// Connect the figures
cf.setStartConnector(ta.findConnector(Geom.center(ta.getBounds()), cf));
cf.setEndConnector(tb.findConnector(Geom.center(tb.getBounds()), cf));
// Add all figures to a drawing
Drawing drawing = new DefaultDrawing();
drawing.add(ta);
drawing.add(tb);
drawing.add(cf);
// Show the drawing
JFrame f = new JFrame("My Drawing");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(400,300);
DrawingView view = new DefaultDrawingView();
view.setDrawing(drawing);
f.getContentPane().add(view.getComponent());
f.setVisible(true);
}
});
}
Here is the code I am using to extract the calls from method run() to the constructors. The problem that I have is that the last line: String constructorClassName= cons.getExecutable().getDeclaringType().toString(); is returning the wrong class name, instead of getting "jhot.draw.TextAreaFigure()" as the name I am getting "jhot.mini.samples.TextAreaFigure()". The file that I am parsing is located under "jhot.mini.samples" while the constructor is declared within "jhot.draw.TextAreaFigure()". I am not sure if this is a bug in spoon or if I am using the wrong API to retrieve the constructor calls.
for(CtMethod<?> method :clazz.getMethods()) {
List<CtConstructorCall> ctNewClasses = method.getElements(new TypeFilter<CtConstructorCall>(CtConstructorCall.class));
for( CtConstructorCall myclass: ctNewClasses) {
//CONSTRUCTOR
if(myclass instanceof CtConstructorCall<?>) {
System.out.println("yes");
List<CtMethod> methoddeclared = myclass.getElements(new TypeFilter<CtMethod>(CtMethod.class));
for(CtMethod<?> meth: methoddeclared) {
methodinside=meth.getSignature();
methodinsideclass=clazz.getQualifiedName();
String mymethod=methodinsideclass+"."+methodinside;
ResultSet methodsinside = st.executeQuery("SELECT methods.* from methods where methods.fullmethod='"+mymethod+"'");
//while(callingmethodsrefined.next()){
if(methodsinside.next()) {
MethodIDINSIDE = methodsinside.getString("id");
CLASSNAMEINSIDE = methodsinside.getString("classname");
CLASSIDINSIDE = methodsinside.getString("classid");
//System.out.println("CALLEE METHOD ID: "+ CALLEEID);
}
List<CtConstructorCall> constructors = meth.getElements(new TypeFilter<CtConstructorCall>(CtConstructorCall.class));
for(CtConstructorCall<?> cons: constructors) {
String constructorClassName= cons.getExecutable().getDeclaringType().toString();
}
}
}
}
I am not sure if this is a bug in spoon or if I am using the wrong API to retrieve the constructor calls.
I'm one of the contributor of Spoon. It looks to me that you're using the right API, but I'm not sure because your example looks a bit messy here.
I think it would be easier if you open an issue on Spoon Github repository and specify:
the project you're working on if it's open-source
how you launch Spoon (the version of Spoon, arguments, etc)
what do you expect exactly
Then we could investigate to check exactly what happens there. Thanks!
I am trying to unit test a class which extends org.eclipse.ui.views.properties.tabbed.AbstractPropertySection
It is a GUI on top of a heap of legacy code. The AbstractPropertySection class have a
private TabbedPropertySheetPage tabbedPropertySheetPage;
field, which is initialized by its
public void createControls(Composite parent,
TabbedPropertySheetPage aTabbedPropertySheetPage)
method, and used by its
public TabbedPropertySheetWidgetFactory getWidgetFactory();
method, which in turn used by widget creation. I cannot mock it up in a way that creating a Button would actually create one. As it is both legacy and GUI, maybe it would be wiser to use the Real Thing? But how?
I am doing basically this:
private LineDecorationSection section;
private DiagramConnectionMockup data;
//contains both the model object and editPart
data = new DiagramConnectionMockup();
ConnectionDecorationFactory.getInstance();
//a descendant of the class to be tested,
//augmented with methods to handle what would be done and seen
//on the GUI
section = new LineDecorationSectionExerciser();
assertTrue(section instanceof LineDecorationSection);
//a selection containing theeditPart
ISelection selection = new SelectionMockup(data.getEditPart());
//an editor (Legacy)
IWorkbenchPart editor = new ZentaDiagramEditor();
section.setInput(editor, selection);
//------------This fails-----------
assertNotNull(section.getWidgetFactory());
LineDecorationSectionExerciser exerciser = (LineDecorationSectionExerciser)section;
Button but = ((Button)exerciser.getInternal("DefaultButton"));
//----and this prints "but=null"------------
System.out.println("but="+but);
but.setSelection(true);
The actual code is here: https://github.com/magwas/zenta/blob/001f83c8951a4840b84cd1ff402baa5b96feb4e5/org.rulez.magwas.zenta.editor/src/org/rulez/magwas/zenta/tests/propertysections/LineDecorationSectionTest.java
Question: what to add to the unit tests and mockups so that the unit tests run, and widgets get created?
In the end I have come up with real underlying data and mockups for the Property Sheet page and the goo coming with it. Maybe not the best solution, but I have put the mockup initialisation into the exerciser class.
The solution for the real-world problem is here:
https://github.com/magwas/zenta/blob/51fd9f6b9e363eb5967a3d24b22d012b5bdd6492/org.rulez.magwas.zenta.editor/src/org/rulez/magwas/zenta/tests/propertysections/LineDecorationSectionTest.java
I am building a user interface in netBeans (coding by hand, more flexible) with multiple toolbars.
What I am trying to do is create an actionListener for each button. I am retrieving names of the functions from XML and parse them to string. I will write implementations for those functions in a separate class, but my problem is the following:
How do I make the link between the function name and the string containing it's name?
Example: String is Open(), function will be Open(someParameter) and in the definitions class there will be static void Open(param).
First of all, consider my comment about your idea of dynamic button behavior resolved from strings being a wrong approach. However if you still need exactly what you asked, what you need is Reflection API.
Here's an example:
Class c = SomeClassWithMethods.class;
Method m = c.getMethod("someMethodName", String.class, Integer.class, Integer.TYPE);
m.invoke(baseObjectFromWhichToCallTheMethod, "stringParam", 10, 5);
Added:
Another option, which is a little bit prettier than reflection, but still a messy design, would be to use a map to link those Strings to methods. The code is a bit longer, but from the Java perspective it is much better than using reflection for your task (unless you have some specific requirement of which I'm not aware). This is how it would work:
//Interface whose instances will bind strings to methods
interface ButtonClickHandler {
void onClick();
}
class SomeClassYouNeed {
//One of the methods that will be bound to "onButtonOneClick()"
public void onButtonOneClick() {
log.info("ButtonOneClick method is called");
}
public void onButtonTwoClick() {
log.info("ButtonTwoClick method is called");
}
//Map that will hold your links
private static Map<String, ButtonClickHandler> buttonActionMap;
//Static constructor to initialize the map
static {
buttonActionMap = new Map<String, ButtonClickHandler>();
buttonActionMap.put("onButtonOneClick()",new ButtonClickHandler() {
#Override
public void onClick() {
onButtonOneClick();
}
});
buttonActionMap.put("onButtonTwoClick()",new ButtonClickHandler() {
#Override
public void onClick() {
onButtonTwoClick();
}
});
}
public void callByName(String methodName) {
final ButtonClickHandler handler = buttonActionMap.get(methodName);
if (handler == null) {
throw new IllegalArgumentException("No handler found by name: "+methodName);
}
handler.onClick();
}
}
After you call callByName("onButtonTwoClick()") it will fetch the respective instance of ButtonClickHandler which will use the static method onButtonTwoClick() to process the click of the button.
It seems to me that you are looking for the equivalent of JS "eval" function in Java. This might help. Nevertheless it is generally not a good idea as #Max stated, you might want to rethink your design.
If i have understood your question correctly you are trying to generate your code files based on some strings taken from a XML file. I can suggest you this library to generate your codes.
For tutorials you can visit this link.
You may even use the Java Reflection API. Here is a link for the tutorial.
Its upto you, that which of the above two you use.
I'm having some problems with localization in wicket.
This is the code:
private String displayString;
private TextField<String> myTextField;
public myPage(DomainObject domainObject){
if(domainObject != null)
displayString = domainObject.getDisplayString();
myTextField = new TextField<String>("myTextField", new PropertyModel<String>(this, "displayString"));
if(Strings.isEmpty(displayString))
displayString = getString("mandatory"); //<- error message here
}
The problem is that calling getString in the constructor results in an error message("...This can sometimes lead to an invalid or no localized resource returned...").
I want to use a PropertyModel for the TextField since I don't want to translate the string I get from domainObject.getDisplayString(). I don't want the changes made in the TextField to affect the value in domainObject directly.
It's possible to get rid of the error message by doing this instead of getString:
if(Strings.isEmpty(displayString))
displayString = new ResourceModel("mandatory").getObject(); //<- no error message
To my understanding, this is the same thing as calling getString (you just hack away the warnings, but the problem still exist).
A solution i thought of is this:
#Override
protected void onAfterRender() {
super.onAfterRender();
if(Strings.isEmpty(displayString))
displayString = getString("mandatory"); //<- no error message
}
Does anyone see a problem with this solution? Maybe I'm not thinking "wickety" enough?
Calling getString() requires the component to be inside a component hierarchy, where it can access it's parent to have the chance to fall back to properties defined there or further up in the tree. This isn't possible inside the component's constructor (as you add it to it's parent at a later point). Wicket 1.5 introduces the onInitialize function for these operations. With Wicket versions prior to this, there is an easy way to emulate this behaviour:
In your base component and page define a non-final empty method as
protected void onInitialize() {}
and add this to the onBeforeRender method:
protected void onBeforeRender() {
...
if (!hasBeenRendered()) {
onInitialize();
}
...
}
Then you can use an overridden onInitialize() method in any of your components to deal with stuff that has to wait until the component hierarchy is established.
What about a reusable behavior:
public class MandatoryBehavior extends AbstractBehavior {
public void onComponentTag(Component component, ComponentTag tag) {
if (((AbstractTextComponent)component).isRequired() && Strings.isEmpty(tag.get("value"))) {
tag.put("value", component.getString("mandatory"));
}
}
}
You'd have to check submitted values in a validator though.
HTML5 placeholders are even nicer.