Custom action using custom command class and dialog in magnolia - magnolia

I would like to have a custom action on the pages app that opens up a dialog with one field for a comment and two actions, namely cancel and commit. The commit action calls the custom ExportToGitCommand class.
I defined a custom action definition and class action for the pages app in magnolia:
public class ExportToGitCommandAction extends AbstractCommandAction<ExportToGitCommandActionDefinition>{
public ExportToGitCommandAction(ExportToGitCommandActionDefinition definition, JcrItemAdapter item,
CommandsManager commandsManager, UiContext uiContext, SimpleTranslator i18n) {
super(definition, item, commandsManager, uiContext, i18n);
// TODO Auto-generated constructor stub
}
public ExportToGitCommandAction(ExportToGitCommandActionDefinition definition, List<JcrItemAdapter> items,
CommandsManager commandsManager, UiContext uiContext, SimpleTranslator i18n) {
super(definition, items, commandsManager, uiContext, i18n);
// TODO Auto-generated constructor stub
}
}
In the Config app I defined myAction:
MyAction
class ->ch.xxx.module.versioning.ExportToGitCommandActionDefinition
command -> /modules/xxx-module-versioning/commands/versioning/gitexport
dialogName -> /modules/xxx-module-versioning/dialogs/saveversion
The constructor in ExportToGitCommandActiongets invoked but the dialog and command from myAction are not. What methods do I need to implement so that the myAction:
opens a dialog
executes the custom command
The custom command gitexport code is:
public class ExportToGitCommand extends BaseRepositoryCommand {
#Override
public boolean execute(Context context) throws Exception {
//custom code here
}
}
Part of the solution
Under the pages app I created an action using the following configuration:
MyAction
class ->i nfo.magnolia.ui.framework.action.OpenCreateDialogActionDefinition
dialogName -> xxx-module-versioning:gitexport
icon -> icon-i-beacon
label -> MyAction
Under the xxx-module-versioning app I configured the dialog:
xxx-module-versioning
commands
dialogs
gitexport
form
actions

I think you have made an error in definition of your action. You need to specify "name" of the command in your catalog, not path to it. And you need to specify catalog name if it is different from "default".
Try this:
MyAction
class ->ch.xxx.module.versioning.ExportToGitCommandActionDefinition
command -> gitexport
catalog -> versioning
dialogName -> /modules/xxx-module-versioning/dialogs/saveversion

This is a possible solution that worked.
In the magnolia pages app in magnolia configuration configure a custom action:
In the respective module defined under dialogName define the dialog:
The custom class extends CommandActionDefinition:
public class ExportToGitCommandActionDefinition extends CommandActionDefinition{
public ExportToGitCommandActionDefinition() {
this.setImplementationClass(ExportToGitCommandAction.class);
}

Related

Can I Bind to Something Global in Xamarin Forms?

I would like to display the current user in a custom view, which most of my ContentPage's contain. I currently store the current user in the App instance as a property, after login. Attempting to just update the Label in the constructor is too early in the lifecycle.
Is there a way with Xamarin Forms to bind to this object or otherwise get the current user to update a Label in my custom view? I am using Xamarin.Forms 3.5 with the standard MVVM.
There are a multiple approaches you could take, but the short answer is that you need something sitting between the global (static) variable and the views in order to make things work smoothly. The property on your view model must be a non-static property.
However it can have a custom implementation so that the getter retrieves the value from some global location, and in your case, you may not need a setter. The only other piece you need is to tell the view model to fire a PropertyChanged event when the user information is available, then you can use standard Binding from the Label to the view model.
Assuming you have some CurrentUser static class that has members like:
public static class CurrentUser
{
public event Action OnLogin; // login code needs to fire this on login
public string Username { get; set; }
// etc.
}
Then view models would hook up to that by doing something like:
class UserViewModel : INotifyPropertyChanged
{
public UserViewModel()
{
CurrentUser.OnLogin += CurrentUser_Login;
}
private void CurrentUser_Login()
{
PropertyChanged?.Invoke(nameof(Username));
}
public string Username {
get {
return CurrentUser.Username;
}
}
// etc.
}
Then the view would use <Label Text="{Binding Username}" . . .> and then when OnLogin is fired, all views would be automatically updated with the new username.

JavaFX call default method in SceneBuilder (FXML)

How can I call a interface default method in the FXML - scenebuilder.
I have an Interface like:
public interface Startable
{
default void handleStart(){...}
}
and a controller like:
BlaController implements Startable {...}
but if I call the method "handleStart()" in the fxml, I get the following exception:
javafx.fxml.LoadException: Error resolving onMouseClicked='#handleStart', either the event handler is not in the Namespace or there is an error in the script.
Is there a possibility to call the method?
It is not possible to implement an interface default method and use it in FXML, apparently FXMLLoader uses reflection and doesn't find the method in the class implementation. You must override the method in the Controller class and then call the default method.
The interface remains the same.
public interface Startable {
default void handleStart(){...}
}
This is how you can call the super implementation
public class BlaController implements Startable {
#Override
#FXML
void handleStart(){
Startable.super.handleStart();
}
}
Hope it helps...
I have created a feature request. Maybe there will be a straight forward solution to this question in the future: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8259916

SysOperation Framework - CanGoBatchJournal

When canGoBatchJournal returns true, a RunBaseBatch can be created in Ax via the System administartion > Inquiries > Batch > New > Task > New >[ClassName:MyRunBaseBatch].
I have a couple of features which have been created using the SysOperation framework however. This method doesn't inherit the canGoBatchJournal method. Is there a way to make them visible in the above mentioned menu as well?
I took a dive into how to form control retrieves it's data. There is an SysOperationJournaledParametersAttribute attribute which you can use.
Below is an example of how the attribute would be applied to a controller. This example shows how the controller calls the custom service. The controller can then be used in as a batch task or you could call the controller from a menu to get the batch dialog to display.
[SysOperationJournaledParametersAttribute(true)]
class YourCustomController extends SysOperationServiceController
{
public void new()
{
super();
this.parmClassName(classStr(YourCustomService));
this.parmMethodName(methodStr(YourCustomService,processOperation));
this.parmDialogCaption("dialog caption");
}
public ClassDescription caption()
{
return "class description";
}
public static void main(Args args)
{
YourCustomController controller;
controller = new YourCustomController();
controller.startOperation();
}
}
Below would be the custom service the controller calls.
class YourCustomToolService extends SysOperationServiceBase
{
public void processOperation()
{
// Call your code to do run your custom logic
}
}
If you implement the SysOperation framework, it should already be good as SysOperationController implements the Batchable interface.
You can refer to this white paper: https://www.microsoft.com/en-us/download/details.aspx?id=29215

Calling a non-parental Activity method from fragment without creating a new instance

I have my MainActivity and inside that I have a number of fragments. I also have another activity that works as my launcher and does everything to do with the Google Drive section of my app. On start up this activity launches, connects to Drive and then launches the MainActivity. I have a button in one of my fragments that, when pushed, needs to call a method in the DriveActivity. I can't create a new instance of DriveActivity because then googleApiClient will be null. Is this possible and how would I go about doing it? I've already tried using getActivity and casting but I'm assuming that isn't working because DriveActivity isn't the fragments parent.
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//TODO for test only remove
directory = new Directory(SDCARD + LOCAL_STORAGE);
byte[] zippedFile = directory.getZippedFile(SDCARD + STORAGE_LOCATION + directory.getZipFileName());
//Here I need to somehow call DriveActivity.uploadFileToDrive(zippedFile);
//((DriveActivity)getActivity()).uploadFileToDrive(zippedFile);
}
});
Right, so I'm having a bit of difficulty with the heirarchy but I think what you want to do is define a method in the fragment that the activity will be required to override to use.
This will allow you to press the button, and then fire a method whos actual implementation is inside the parent.
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(String id);
}
example implementation:
private static Callbacks sDummyCallbacks = new Callbacks() {
#Override
public void onItemSelected(String id) {
//Button fired logic
}
};
so in the child you'd do just call:
this.onItemSelected("ID of Class");
EDITED
In retrospect what I believe you need is an activity whos sole purpose is to upload files, not fire off other activities.
Heres an example of a 'create file' activity:Google Demo for creating a file on drive
Heres an example of the 'base upload' activity' Base Service creator

Can I create custom global methods in my Android Application class?

I currently have an app that has many activities and needs to have a way of maintaining state between these activities.
I use the Application class to do this, declaring my global variables and using getters and setters to interact with my activities.
I was hoping to place a few custom methods in there, so that when I want to do a common task like, for instance, display an error message, I can declare the method in my application class and call it from any activity that uses it
EscarApplication application = (EscarApplication) this.getApplication();
EscarApplication being the name of my application class above.
I have tried to include this method in my application class:
public void showError(String title, String message) {
Log.i("Application level",message);
this.alertDialog.setTitle(title);
alertDialog.setMessage(message);
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
return;
}
});
alertDialog.show();
}
In the hope that I can call this method from activity without having to redeclare it, but when I call it using something like below I get an null pointer exception:
Visit.this.application.showError("Update error", "An error has occurred while trying to communicate with the server");
Visit being the name of my current activity above.
Should this work, or can I only use getters and setters to change global vars in an Application Class.
Stack Trace:
java.lang.RuntimeException: Unable to start activity ComponentInfo{escar.beedge/escar.beedge.HomeScreen}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2401)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
at android.app.ActivityThread.access$2100(ActivityThread.java:116)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4203)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
at dalvik.system.NativeStart.main(Native Method)
ERROR/AndroidRuntime(375): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
at android.view.ViewRoot.setView(ViewRoot.java:460)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.app.Dialog.show(Dialog.java:238)
at escar.beedge.EscarApplication.showError(EscarApplication.java:98)
at escar.beedge.HomeScreen.onCreate(HomeScreen.java:30)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
The dialog is declared as such in the application class:
AlertDialog alertDialog;
Created in that same class:
alertDialog = new AlertDialog.Builder(this).create();
and the method to call it in that class is as follows:
public void showError(String title, String message) {
alertDialog.setTitle(title);
alertDialog.setMessage(message);
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
return;
}
});
alertDialog.show();
}
And finally, it is called from an activity like so:
EscarApplication application;
application = (EscarApplication) this.getApplication();
application.showError("test", "display this message");
If you need to maintain state between activities, then use a service. Anything else is a hack
Someone correct me if Im wrong, but an Application class wont be able to execute view related objects as they need to be bound to a view which needs to be bound to an activity.
In that sense, you could use your Application class to implement a static method that customises the dialog
public static void setDialog(String title, String message,AlertDialog alertDialog){
alertDialog.setTitle(title);
alertDialog.setMessage(message);
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
return;
}
});
}
but you would have to create the dialog and call the show method on the activities themselves (actually maybe even the button to be set in the dialog would need to be created on the activity)
Another option could be to implement a class that extends the AlertDialog class and whose button is pre-set to the behavior you want.
You could use the Singleton pattern.
I'm looking to achieve something similar to you.
I haven't found an official answer, but it looks like you shouldn't be using the application context for Toast and Dialogs. Instead, try using the context of an Activity like so :
// From inside your activity
Dialog dialog = new Dialog(this);
instead of this:
// From inside your Application instance
Dialog dialog = new Dialog(getApplicationContext());
Read this :
Android: ProgressDialog.show() crashes with getApplicationContext

Resources