I've been working in this project for abou a week and haven't find a solution to my problem.
For testing purposes I create a simple new DeclarativeComponent which is a panelGroupLayout that contains 2 OutputText. After that I deploy the jar file and add it to my other Fusion web application libraries.
I want to add this DeclarativeComponent in another UIComponent at runtime by pressing a button which contains the next code in the javabean:
`public void addComponent(ActionEvent actionEvent)
{
// Add event code here...
createOutputComponent();
}
private void createOutputComponent()
{
CuadroDeTextoComponent ui = new CuadroDeTextoComponent(); //This is my Declarative Component
UIComponent parentUIComponent = getPglComponente(); This is the panelGrouopLayout in which i want to add my declarativeComponent
addComponent(parentUIComponent, ui);
}
public void addComponent(UIComponent parentUIComponent, UIXDeclarativeComponent childUIComponent)
{
parentUIComponent.getChildren().add(childUIComponent);
AdfFacesContext.getCurrentInstance().addPartialTarget(parentUIComponent);
}`
I have tried draging the declarative component and it works, but when I do it dynamically the component doesn't display
For your component to display you may need to add a PPR refresh to it's parent element :
In your case :
public void addComponent(ActionEvent actionEvent)
{
// Add event code here...
createOutputComponent();
}
private void createOutputComponent()
{
CuadroDeTextoComponent ui = new CuadroDeTextoComponent(); //This is my Declarative Component
UIComponent parentUIComponent = getPglComponente(); This is the panelGrouopLayout in which i want to add my declarativeComponent
addComponent(parentUIComponent, ui);
addPPR(parentUIComponent); //Refresh the parent component
}
public void addComponent(UIComponent parentUIComponent, UIXDeclarativeComponent childUIComponent)
{
parentUIComponent.getChildren().add(childUIComponent);
AdfFacesContext.getCurrentInstance().addPartialTarget(parentUIComponent);
}
public static void addPPR(UIComponent component) {
if (component != null) {
AdfFacesContext.getCurrentInstance().addPartialTarget(component.getParent());
}
}
Related
I am trying to develop a IntelliJ plugin which provides a Language Server with help of lsp4intellij by ballerina.
Thing is, i've got a special condition: The list of completion items should be editable in runtime.
But I've not found any way to communicate new completionItems to the LanguageServer process once its running.
My current idea is to add an action to the plugin which builds a new jar and then restarts the server with the new jar, using the Java Compiler API.
The problem with that is, i need to get the source code from the plugin project including the gradle dependencies accessable from the running plugin... any ideas?
If your requirement is to modify the completion items (coming from the language server) before displaying them in the IntelliJ UI, you can do that by implementing the LSP4IntelliJ's
LSPExtensionManager in your plugin.
Currently, we do not have proper documentation for the LSP4IntelliJ's extension points but you can refer to our Ballerina IntelliJ plugin as a reference implementation, where it has implemented Ballerina LSP Extension manager to override/modify completion items at the client runtime in here.
For those who might stumble upon this - it is indeed possible to change the amount of CompletionItems the LanguageServer can provide during runtime.
I simply edited the TextDocumentService.java (the library I used is LSP4J).
It works like this:
The main function of the LanguageServer needs to be started with an additional argument, which is the path to the config file in which you define the CompletionItems.
Being called from LSP4IntelliJ it would look like this:
String[] command = new String[]{"java", "-jar",
"path\\to\\LangServer.jar", "path\\to\\config.json"};
IntellijLanguageClient.addServerDefinition(new RawCommandServerDefinition("md,java", command));
The path String will then be passed through to the Constructor of your CustomTextDocumentServer.java, which will parse the config.json in a new Timer thread.
An Example:
public class CustomTextDocumentService implements TextDocumentService {
private List<CompletionItem> providedItems;
private String pathToConfig;
public CustomTextDocumentService(String pathToConfig) {
this.pathToConfig = pathToConfig;
Timer timer = new Timer();
timer.schedule(new ReloadCompletionItemsTask(), 0, 10000);
loadCompletionItems();
}
#Override
public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completion(CompletionParams completionParams) {
return CompletableFuture.supplyAsync(() -> {
List<CompletionItem> completionItems;
completionItems = this.providedItems;
// Return the list of completion items.
return Either.forLeft(completionItems);
});
}
#Override
public void didOpen(DidOpenTextDocumentParams didOpenTextDocumentParams) {
}
#Override
public void didChange(DidChangeTextDocumentParams didChangeTextDocumentParams) {
}
#Override
public void didClose(DidCloseTextDocumentParams didCloseTextDocumentParams) {
}
#Override
public void didSave(DidSaveTextDocumentParams didSaveTextDocumentParams) {
}
private void loadCompletionItems() {
providedItems = new ArrayList<>();
CustomParser = new CustomParser(pathToConfig);
ArrayList<String> variables = customParser.getTheParsedItems();
for(String variable : variables) {
String itemTxt = "$" + variable + "$";
CompletionItem completionItem = new CompletionItem();
completionItem.setInsertText(itemTxt);
completionItem.setLabel(itemTxt);
completionItem.setKind(CompletionItemKind.Snippet);
completionItem.setDetail("CompletionItem");
providedItems.add(completionItem);
}
}
class ReloadCompletionItemsTask extends TimerTask {
#Override
public void run() {
loadCompletionItems();
}
}
}
Refreshing TreeViewer Does Not Work After I Add an Element in the TreeViewer,But Refreshing TreeViewer Work After I Remove an Element in the TreeViewer.
my remove/delete action like this,EntityElement is the basic type of tree node:
public void run() {
// TODO Auto-generated method stub
IStructuredSelection selection = (IStructuredSelection) viewSite.getSelectionProvider().getSelection();
Object firstElement = selection.getFirstElement();
if (firstElement instanceof EntityElement) {
EntityElement entityElement = (EntityElement)firstElement;
entityElement.getParent().removeChildren(entityElement);
tv.refresh(entityElement.getParent(), false);
}
}
My Add Action like this,object is the selected tree node Object:
public void run() {
// TODO Auto-generated method stub
if (object instanceof EntityElement) {
EntityElement demoElement = ((EntityElement) object).getChildren().get(0);
((EntityElement) object).getChildren().add(demoElement); //Add its first child by default
Variable.treeViewer.refresh((EntityElement) object);
}
}
}
I want to ask Why remove action is working but add action not working?
OK.This problem has been solved. When I new EntityElement and add it, call refresh() TreeViewer to refresh and show the new node, I'm curious why
EntityElement demoElement = ((EntityElement) object).getChildren().get(0);
((EntityElement) object).getChildren().add(demoElement);
Does not work???
I'm creating intelliJ plugin and registering my action , inside my action i want to show an input dialog with multiple text boxes, how do I do that ?
I have an example of showing only one text box -
String txt= Messages.showInputDialog(project, "What is your name?",
"Input your name", Messages.getQuestionIcon());
I agree with #AKT with extending the DialogWrapper but suggest overriding doOKAction:
#Override
protected void doOKAction() {
if (getOKAction().isEnabled()) {
// custom logic
System.out.println("custom ok action logic");
close(OK_EXIT_CODE);
}
}
Or, if you just want your data out without the Action mess, add a custom method:
public class SearchDialog extends DialogWrapper {
...
public String getQuery() {
return "my custom query";
}
}
You can use it like:
SearchDialog dialog = new SearchDialog();
dialog.showAndGet(); // Maybe check if ok or cancel was pressed
String myQuery = dialog.getQuery();
System.out.println("my query: " + myQuery);
Create a new GUI Form (form + class). Class should extend DialogWrapper and override methods.
Inside createCenterPanel() return your root JPanel. You can set any default values, add event listeners to text box, etc., before returning JPanel.
Implement an Action interface where you want to get the value when OK button is clicked. Pass this action to your form class.
getOKAction() should return this action.
Following code is from a plugin i'm currently working on. Hopefully this will give you some idea but will have to adapt it to your need.
public class ReleaseNoteDialog extends DialogWrapper implements Action {
private JTextArea txtReleaseNote;
private JPanel panelWrapper;
.......
protected JComponent createCenterPanel() {
......
return panelWrapper;
}
......
#Override
protected Action getOKAction() {
return this;
}
.......
#Override
public void actionPerformed(ActionEvent e) {
// save value to project state
super.doOKAction();
}
If I have for example one master view on the left and one in the middle, each showing oder Java Beans/POJOs, can I use a shared detail view that somehow listens to the active beans of each view and then displays the currently selected one in more detail? A one to one relation is quite easy to manage by using your Context library.
#ViewDocking(areaId ="left", position=1, displayName="Profiles", menuEntry = #WindowMenuEntry(path = "", position=0), accelerator="Shortcut+1")
public class ProfileListView extends BorderPane implements LocalContextProvider {
private final SimpleContextContent content = new SimpleContextContent();
private final SimpleContext context = new SimpleContext(content);
#FXML
private ListView<Profile> listview;
public ProfileListView() {
load();
// add some profiles
listview.getItems().add(new Profile("Profile1"));
listview.getItems().add(new Profile("Profile2"));
listview.getItems().add(new Profile("Profile3"));
// setup selection listener
listview.getSelectionModel().selectedItemProperty().addListener((value, oldProfile, newProfile) -> {
// set active profile and remove old one
content.remove(oldProfile);
content.add(newProfile);
});
// setup double click listener
configureClickListener();
}
private Profile getSelectedProfile() {
return listview.getSelectionModel().getSelectedItem();
}
private void configureClickListener() {
listview.setOnMouseClicked(event -> {
// check if it was a double click
if(event.getClickCount() == 2) {
System.out.println(getSelectedProfile());
// inject into editor pane
// calls the procedure to create a tab in the center area...
}
});
}
private void load() {
FXMLLoaders.loadRoot(this);
}
#Override
public Context getLocalContext() {
return context;
}
}
This is one master view holding a list view of items.
The other one would be the same, docking to the right as another tab and holding POJOs of type 'Action'.
The detail view is here:
#ViewDocking(areaId = "right", displayName = "Properties", accelerator = "Shortcut+2", menuEntry = #WindowMenuEntry(path = "", position = 0), position = 1)
public class ProfilePropertiesView extends BorderPane implements LocalContextProvider, ActiveContextSensitive {
private Context activeContext;
private SimpleContextContent content = new SimpleContextContent();
private SimpleContext context = new SimpleContext(content);
private Profile profile;
private IWindowService service = new NullWindowService();
#FXML
private PropertySheet propertysheet;
public ProfilePropertiesView() {
load();
// retrieve framework service, TODO: use tracker
BundleContext ctx = FrameworkUtil.getBundle(getClass()).getBundleContext();
service = ctx.getService(ctx.getServiceReference(IWindowService.class));
// initialize callback
service.addCallback(title -> {
System.out.println("callback called " + title);
// update the property sheet ui by re-creating the items list
// updateUI();
// we can safely return null
return null;
});
// configure editor factory so the user is able to use a combobox
propertysheet.setPropertyEditorFactory(new CustomPropertyEditorFactory(service));
}
private void load() {
FXMLLoaders.loadRoot(this);
}
#Override
public Context getLocalContext() {
return context;
}
private void contextChanged() {
// find profile information
Profile found = activeContext.find(Profile.class);
// if the found profile is null, ignore it
if (found != null) {
// reset if profile is valid
if (profile != null) {
reset();
}
// create reference and register
profile = found;
register();
}
}
private void register() {
// retrieve observablelist of bean properties if some profile is selected
if(profile != null) {
ObservableList<Item> items = createDetailedList(profile);
propertysheet.getItems().setAll(items);
}
}
private void updateUI() {
// clear property elements and re-create them
reset();
// re-create items
ObservableList<Item> items = createDetailedList(profile);
propertysheet.getItems().addAll(items);
}
private ObservableList<Item> createDetailedList(Object bean) {
ObservableList<Item> list = FXCollections.observableArrayList();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
Arrays.stream(beanInfo.getPropertyDescriptors()).map(pd -> new DetailedBeanProperty(bean, pd)).forEach(list::add);
} catch (IntrospectionException e) {
e.printStackTrace();
}
return list;
}
private void reset() {
propertysheet.getItems().clear();
}
#Override
public void setActiveContext(Context activeContext) {
this.activeContext = activeContext;
this.activeContext.addContextListener(Profile.class, event -> contextChanged());
// trigger change
contextChanged();
}
}
The current ProfilePropertiesView is just configured to display the properties of the selected profile. I want it to be able to display the current information of the last selected POJO in the UI. That means that if the user selected a Profile from the ListView, that profile should be displayed in the properties view. If he selected an Action from the Table (which is displayed in the center), the properties of the Action should be displayed.
Do I just need to register a new ContextListener for the Action.class
POJO and then call a method to populate the PropertiesView? I was
unsure if this is the right solution...
Yes, just add another ContextListener to the activeContext for every POJO type you want to observe.
Also note that in the constructor of views it's better to use a ServiceTracker instead of looking for the service via BundleContext as the service might not be available yet, depending on the order the bundles are loaded.
You can find a sample which uses a ServiceTracker here: https://stackoverflow.com/a/35974498/506855
I need to register different share charm listener for every page. I have 2 pages. I added following code in every one:
DataTransferManager.GetForCurrentView().DataRequested += App_DataRequested;
I added it in constructor of one page and in UserControl_Loaded event of another (first page just doesn't have UserControl_Loaded so why I added it directly to constructor). At the moment when second page tryting to load, I got exception:
WinRT information: An event handler has already been registered
Additional information: A method was called at an unexpected time.
Where should I place it and what is "right" time to do this??
Also it looks confusing that we have different DataTransferManager for every view, but only one is active at current time. Ever more, I noticed, if you add only one listener for first page, other pages will share this listener anyway. If I have only one shared listener for all pages, is it correct register it in app.xaml.cs?
The way I resolved this issue was to deregister the event in the onNavigatedfrom event as below:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
DataTransferManager.GetForCurrentView().DataRequested -= App_DataRequested;
base.OnNavigatedFrom(e);
}
In BasePage.cs in constructor I added
public BasePage()
{
if (!_isListenToDataRequested)
{
_isListenToDataRequested = true;
DataTransferManager manager = DataTransferManager.GetForCurrentView();
manager.DataRequested += AppDataRequested;
}
}
private async void AppDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
IShareable shareable = Frame.Content as IShareable;
if (shareable != null)
{
DataRequestDeferral deferral = args.Request.GetDeferral();
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => shareable.AppDataRequested(sender, args));
deferral.Complete();
}
}
And all my pages look like
public sealed partial class ContentPage : IShareable
{
public void AppDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{...}
}
Another solution was run this as below
private DataTransferManager dataTransferManager;
Put this in page loaded event
this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
{
this.dataTransferManager = DataTransferManager.GetForCurrentView();
this.dataTransferManager.DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(this.OnDataRequested);
}));
And
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
// Unregister the current page as a share source.
this.dataTransferManager.DataRequested -=
new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>
(this.OnDataRequested);
}
I'd suggest doing it in the navigating events, the OnNavigatingFrom event will be triggered before the OnNavigatingTo of the page you're going to so you won't have this problem.
protected override Task OnNavigatingTo(WinRTXamlToolkit.Controls.AlternativeNavigationEventArgs e)
{
DataTransferManager.GetForCurrentView().DataRequested += dataTransfer_DataRequested;
return base.OnNavigatingTo(e);
}
protected override Task OnNavigatingFrom(WinRTXamlToolkit.Controls.AlternativeNavigatingCancelEventArgs e)
{
DataTransferManager.GetForCurrentView().DataRequested -= dataTransfer_DataRequested;
return base.OnNavigatingFrom(e);
}
//Note: This is the WinRT Xaml Toolkit version of the events, but the standard events will work the same way.