Intellij IDEA plugin development: Cannot get progress indicator for IntentionAction - java

I would like to display a progress bar when running a custom IntentionAction in my custom IntellIJ IDEA plugin.
However, it is not displayed no matter what I do. To test whether the problem lies in the IntentionAction, I copy-paste the code to a simple implementation of an AnAction. The whole class looks like so:
public class HelloAction extends AnAction {
public HelloAction() {
super("Hello");
}
public void actionPerformed(AnActionEvent event) {
Project project = event.getData(CommonDataKeys.PROJECT);
ProgressManager.getInstance().run(new Task.Modal(project, "daf", false) {
public void run(ProgressIndicator indicator) {
indicator.setText("This is how you update the indicator");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
indicator.setFraction(0.5); // halfway done
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
}
});
Messages.showMessageDialog(project, "Hello world!", "Greeting", Messages.getInformationIcon());
}
}
And it works perfectly. And when I use the same code inside an IntentionAction, nothing is displayed.
public class GenerateIntentionAction extends PsiElementBaseIntentionAction implements IntentionAction {
...
public void invoke(#NotNull Project project, Editor editor, #NotNull PsiElement element) throws IncorrectOperationException {
ProgressManager.getInstance().run(new Task.Modal(project, "daf", false) {
public void run(ProgressIndicator indicator) {
indicator.setText("This is how you update the indicator");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
indicator.setFraction(0.5); // halfway done
try {
Thread.sleep(2000);
} catch (InterruptedException e) {}
}
});
I tried to run call runWithProgressSynchronously instead of run, tried making Task Modal and Backgroundable - to no avail. I do not know what is wrong besides the fact that ProgressIndicator inside IntentionAction is always an EmptyProgressIndicator

If your intention action is invoked inside WriteAction, you can't show modal UI from there. Overriding startInWriteAction and returning false might help.

Related

JavaFX thread issue

i'm using thread to resolve the problem of GUI freeze. But with thread i'm facing a problem that i'm unable to pass format of the report as argument in run method or even with the help of constructor i'm unable to do it.....
public class BirtReportExportCon implements Runnable {
#FXML
Button exportButton;
#FXML
CheckBox pdfCheckBox;
#FXML
CheckBox xlsCheckBox;
#FXML
CheckBox docCheckBox;
#FXML
CheckBox mailCheckBox;
public String fileFormat;
Allow to Check Single CheckBox on Gui
public void eventCheckBoxPdf() {
if (pdfCheckBox.isSelected() == true) {
xlsCheckBox.setSelected(false);
docCheckBox.setSelected(false);
}
}
public void eventCheckBoxXls() {
if (xlsCheckBox.isSelected() == true) {
pdfCheckBox.setSelected(false);
docCheckBox.setSelected(false);
}
}
public void eventCheckBoxDoc() {
if (docCheckBox.isSelected() == true) {
pdfCheckBox.setSelected(false);
xlsCheckBox.setSelected(false);
}
}
Provide the Chosen fileFormat
public void onButtonClick() throws EngineException {
if (docCheckBox.isSelected() == true) {
fileFormat = "docx"; // I WANT THIS FILE FORMAT IN MY RUN METHOD
Runnable r = new BirtReportExportCon();
new Thread(r).start();
}
else if (pdfCheckBox.isSelected() == true) {
fileFormat = "pdf";
Runnable r = new BirtReportExportCon();
new Thread(r).start();
}
else if (xlsCheckBox.isSelected() == true) {
fileFormat = "xls";
Runnable r = new BirtReportExportCon();
new Thread(r).start();
}
}
Run Method
public void run()
{
try
{
exportFile(fileFormat); // HERE I WANT THAT SO I CAN ABLE TO CREATE REPORT OF REQUIRED FORMAT
}
catch (EngineException e) {
e.printStackTrace();
}
}
save report and open the report
public void exportFile(String fileFormat) throws EngineException {
String output = "output path";
String reportDesignFilePath = "report path";
try {
EngineConfig configure = new EngineConfig();
Platform.startup(configure);
IReportEngineFactory reportEngineFactory = (IReportEngineFactory) Platform
.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
IReportEngine engine = reportEngineFactory.createReportEngine(configure);
engine.changeLogLevel(Level.WARNING);
IReportRunnable runnable = engine.openReportDesign(reportDesignFilePath);
IRunAndRenderTask task = engine.createRunAndRenderTask(runnable);
IRenderOption option = new PDFRenderOption();
option.setOutputFormat(fileFormat);
option.setOutputFileName(output + fileFormat);
task.setRenderOption(option);
task.run();
task.close();
} catch (Exception e) {
e.printStackTrace();
}
// Open Created File
File fileOpen = new File(output + fileFormat);
if (fileOpen.exists()) {
if (Desktop.isDesktopSupported()) {
try {
Desktop desktop = Desktop.getDesktop();
desktop.open(fileOpen);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I had a similar problem like this. I think the problem lies in the fileOpening stage. The Desktop class you are using comes from java.awt package.When you use the Desktop class then the JAVAFX thread gets blocked as commented by a user in the link given at the bottom of this answer. But the user has a low reputation (only 11)so we cannot rely on him.
To make your application unfreeze, you will have to create a new Thread.
Here is a part of my code, i used in my application and this code worked perfectly. I have also put a link to a github issue of my application where i stated the freezing problem, similar to yours. The issue was created 2 days ago.
#FXML
void openWithAction(ActionEvent event) {
boolean flag = false;
Task task = new Task<Void>() {
#Override
protected Void call() throws Exception {
try {
Desktop.getDesktop().open(new File(fileModel.getFileLocation()));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
new Thread(task).start();
}
Github issue link:
https://github.com/karanpant/SearchEverything/issues/3
I also suggest you to use concurrency provided by JavaFX.
Here is the other SO post link. Hope this helps.
JavaFX Freeze on Desktop.open(file), Desktop.browse(uri)
EDIT: I am sorry if i don't understand your question . Is your question about application freezing or about not being able to pass a parameter or about not being able to pass a parameter because of application freezing.
Try something like this:
if ( docCheckBox.isSelected() == true ) {
BirtReportExportCon r = new BirtReportExportCon();
r.fileFormat = "docx"; // I WANT THIS FILE FORMAT IN MY RUN METHOD
new Thread(r).start();
}
You should run this code on the Swing thread instead of calling it from the Java FX thread. Like the following:
#FXML
void openWithAction(ActionEvent event) {
SwingUtilities.invokeLater( () -> Desktop.getDesktop().
open(new File(fileModel.
getFileLocation())));
}

Basic layout/structure of a Java Applet

I have a very simple Java applet that just works.
import java.sql.*;
import org.apache.commons.lang3.*;
public class doQuery {
public static void main (String[] args) {
...
try {
...
} catch (Exception e) {
...
}
try {
...
try {
...
} catch (SQLException e) {
...
} finally {
...
}
} catch (SQLException e) {
...
}
}
}
It allows me to open a database, do some queries, and perform a series of outputs that is captured through stdio of a bash script, connections closed and then bash script emails the output.
However, I am looking to expand it, and I am stuck. I am programmer, just not a Java programmer. What I have come up with is something I hacked together. I want to add some functions, and more. I have tried to the function definitions in different places in the code, but it always generates compilation errors.
Can anyone provide some insight as to what I can change to enable me to add some functions? Generally programming say define the function before you attempt to use it, but I probably am not using the right keywords or something.
I can not figure out where to place a simple function like:
function display_number(number) {
return number + "";
}
in the source code that I can call and have it compile! :(
import java.sql.*;
import org.apache.commons.lang3.*;
public class doQuery {
public static void main (String[] args) {
...
try {
...
} catch (Exception e) {
...
}
try {
...
try {
...
} catch (SQLException e) {
...
} finally {
...
}
} catch (SQLException e) {
...
}
displayNumber(4); // Replace 4 with a variable to output or what not
}
private int displayNumber(int number) {
return number;
}
}
In Java you'll add your methods inside the scope of the class like so, when you want to use them call them inside of another function like in the example above. I'd recommend reading this link, it should give you a good understanding of how methods work, how to call them, etc.
If you just want a quick and easy function, here is a layout you can use.
public void display_number(int number) {
System.out.print(number);
}
Or if you prefer returning the number to use it somewhere else...
public int display_number() {
return number;
}
Your methods can be basically anywhere between the start { and the end } of your class, assuming you do not place it inside another method (such as the main method from your code). As far as anything else I recommend reading up on the subject, I am sure a google search will give you millions of examples of method calls.

Class dosen't match itself from 2 seperate projects

I have a function that uses an org.eclipse.swt.widget.Display as a parameter. I use that project as a library for another project and call that function and use the same class, but my IDEs (eclipse and ItelliJ IDEA CE) are saying that the parameter is not expected.
What's wrong there?
Here is the Code:
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
startServer(port, getSession());
} catch (RmiException e) {
e.printStackTrace();
SWTErrorDialog.show(e, "Error while attaching JavaEngineServer to rmiregistry.exe", Display.getDefault());
}
return null;
}
});

Modifier trouble

I'm using an event system based on the suggestions in this question: Create Custom Event in Java
I implemented it in a component to handle and passthrough the events from a button on the component. I put the component into it's own jar file. Then I used the component and jar file in another project and when I tried to run the program I had created with it, it gave me the following error:
java.lang.IllegalAccessException: Class Eventing.EventHandler can not access a member of class outfit.proto.frmDo$1 with modifiers "public"
This is the code of the EventHandler class I wrote:
public class EventHandler<T> {
private ArrayList<T> listenerPool = new ArrayList<>();
public void addListener(T listener){
listenerPool.add(listener);
}
public void raiseEvent(Object eventData){
for (T listener : listenerPool){
try {
if (eventData != null) {
listener.getClass().getDeclaredMethods()[0].invoke(listener, eventData);
} else {
listener.getClass().getDeclaredMethods()[0].invoke(listener);
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Logger.getLogger(EventHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
This is how I setup the the EventHandler class on the component:
EventHandler<EventListener> _loginEvent = new EventHandler<>();
public EventHandler<EventListener> loginEvent(){
return _loginEvent;
}
loginButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
_loginEvent.raiseEvent(null);
}
});
This is what I did to catch the events on frmDo:
this.component2.loginEvent().addListener(new EventAdapter() {
#Override
public void executeResult() {
}
});
Based on this wikipedia entry on Observer Patterns I got the event system to work! As I suspected Java has some pre-defined system for these kind of things.

Java exception handling in non sequential tasks (pattern/good practice)

There are some task that should't be done in parallel, (for example opening a file, reading, writing, and closing, there is an order on that...)
But... Some task are more like a shoping list, I mean they could have a desirable order but it's not a must..example in communication or loading independient drivers etc..
For that kind of tasks,
I would like to know a java best practice or pattern for manage exceptions..
The java simple way is:
getUFO {
try {
loadSoundDriver();
loadUsbDriver();
loadAlienDetectorDriver();
loadKeyboardDriver();
} catch (loadSoundDriverFailed) {
doSomethingA;
} catch (loadUsbDriverFailed) {
doSomethingB;
} catch (loadAlienDetectorDriverFailed) {
doSomethingC;
} catch (loadKeyboardDriverFailed) {
doSomethingD;
}
}
But what about having an exception in one of the actions but wanting to
try with the next ones??
I've thought this approach, but don't seem to be a good use for exceptions
I don't know if it works, doesn't matter, it's really awful!!
getUFO {
Exception ex=null;
try {
try{ loadSoundDriver();
}catch (Exception e) { ex=e; }
try{ loadUsbDriver();
}catch (Exception e) { ex=e; }
try{ loadAlienDetectorDriver();
}catch (Exception e) { ex=e; }
try{ loadKeyboardDriver()
}catch (Exception e) { ex=e; }
if(ex!=null)
{ throw ex;
}
} catch (loadSoundDriverFailed) {
doSomethingA;
} catch (loadUsbDriverFailed) {
doSomethingB;
} catch (loadAlienDetectorDriverFailed) {
doSomethingC;
} catch (loadKeyboardDriverFailed) {
doSomethingD;
}
}
seems not complicated to find a better practice for doing that.. I still didn't
thanks for any advice
Consider the execute around idiom.
Another option (which isn't really all that different, it just decouples them more) is to do each task in a separate thread.
Edit:
Here is the kind of thing I have in mind:
public interface LoadableDriver {
public String getName();
public void loadDriver() throws DriverException;
public void onError(Throwable e);
}
public class DriverLoader {
private Map<String, Exception> errors = new HashMap<String, Exception>();
public void load(LoadableDriver driver) {
try {
driver.loadDriver();
} catch (DriverException e) {
errors.put(driver.getName(), e);
driver.onError(e);
}
}
public Map<String, Exception> getErrors() { return errors; }
}
public class Main {
public void loadDrivers() {
DriverLoader loader = new DriverLoader();
loader.loadDriver(new LoadableDriver(){
public String getName() { return "SoundDriver"; }
public void loadDriver() { loadSoundDriver(); }
public void onError(Throwable e) { doSomethingA(); }
});
//etc. Or in the alternative make a real class that implements the interface for each driver.
Map<String, Exception> errors = loader.getErrors();
//react to any specific drivers that were not loaded and try again.
}
}
Edit: This is what a clean Java version would ultimately look like if you implemented the drivers as classes (which is what the Java OO paradigm would expect here IMHO). The Main.loadDrivers() method would change like this:
public void loadDrivers(LoadableDriver... drivers) {
DriverLoader loader = ...
for(LoadableDriver driver : drivers) {
loader.load(driver);
}
//retry code if you want.
Set<LoadableDriver> failures = loader.getErrors();
if(failures.size() > 0 && tries++ > MAX_TRIES) {
//log retrying and then:
loadDrivers(drivers.toArray(new LoadableDriver[0]));
}
}
Of course I no longer use a map because the objects would be self-sufficient (you could get rid of the getName() method as well, but probably should override toString()), so the errors are just returned in a set to retry. You could make the retry code even simpler if each driver was responsible for knowing how often it should it retry.
Java won't look as nice as a well done C++ template, but that is the Java language design choice - prefer simplicity over complex language features that can make code hard to maintain over time if not done properly.
Try this:
protected void loadDrivers() {
loadSoundDriver();
loadUsbDriver();
loadAlienDetectorDriver();
loadKeyboardDriver();
}
Then:
protected void loadSoundDriver() {
try {
// original code ...
}
catch( Exception e ) {
soundDriverFailed( e );
}
}
protected void soundDriverFailed( Exception e ) {
log( e );
}
This gives subclasses a chance to change the behaviour. For example, a subclass could implement loading each driver in a separate thread. The main class need not care about how the drivers are loaded, nor should any users of the main class.
IMO, for your case, if the exception is "ignorable" it's best if the "loadSoundDriver" method catches the exception and simply returns an error.
Then in the function that loads stuff, you can record all the errors and at the end of the sequence, decide what to do with them.
[edit]
Something like this:
// init
MyError soundErr = loadSoundDriver();
MyError otherErr = loadOtherDriver();
if(soundErr!=null || otherErr !=null){
// handle the error(s)
}
Just surround every single load operation with its own try / catch block.
try {
loadSoundDriver();
} catch (loadSoundDriverFailed) {
doSomethingA;
}
try {
loadUsbDriver();
} catch (loadUsbDriverFailed) {
doSomethingB;
}
// ...
So you can handle every exception by itself and continue processing the oder operations.

Categories

Resources