How do I print the content of a TextArea? - javafx

So currently I'm trying to make a print feature for my Notepad application. I already have a kind of working Print feature, but it prints the full TextArea not only the string that is written into it.
I already tried to make it just print a string, but the PrintJob is not able to handle it, because it needs the actual TextArea, where the Text is written into.
My current Print Stuff:
public void doPrint() {
String toPrint = writeArea.getText();
printSetup(writeArea, Main.primaryStage);
}
private final Label jobStatus = new Label();
private void printSetup(Node node, Stage owner)
{
// Create the PrinterJob
PrinterJob job = PrinterJob.createPrinterJob();
if (job == null)
{
return;
}
// Show the print setup dialog
boolean proceed = job.showPrintDialog(owner);
if (proceed)
{
print(job, node);
}
}
private void print(PrinterJob job, Node node)
{
// Set the Job Status Message
jobStatus.textProperty().bind(job.jobStatusProperty().asString());
// Print the node
boolean printed = job.printPage(node);
if (printed)
{
job.endJob();
}
}
What I want to have:
A print that only shows the String, just like any other notepad application does if you try to print something
What I currently get:
The full textarea with frame.

As I mentioned in the comment you can wrap it into a Text, but then the first line for some reason isn't displayed correctly.
The solution would be to use a Label instead like:
printSetup(new Label(toPrint), Main.primaryStage);

Related

picocli CLI parser: hide the Java variable name while rendering the output

I am using picocli to show the usage of my command-line application.
What I am not able to reach is to hide the name of the Java variable which appears in the printed output and from my point of view it looks so ugly.
This is the configutation of my CommandLine.Option:
#CommandLine.Option(
names = {"-a", "--abc"},
description = "Please, hide the Java variable name...")
private String xxx;
And this is how it is rendered:
-a, --abc=<xxx> Please, hide the Java variable name...
As you can see the name of the Java variable appears after the equal sign: <xxx>
I would like to hide it, like this:
-a, --abc Please, hide the Java variable name...
I checked the API but I could not see anything related to this.
Is there any way to turn it off?
The picocli annotations API does not provide for this, but it is possible to achieve this by overriding the Help API and plugging in your own option renderer. For example:
public class HideOptionParams {
#Option(names = {"-u", "--user"}, defaultValue = "${user.name}",
description = "The connecting user name.")
private String user;
#Option(names = {"-p", "--password"}, interactive = true,
description = "Password for the user.")
private String password;
#Option(names = {"-o", "--port"}, defaultValue = "12345",
description = "Listening port, default is ${DEFAULT-VALUE}.")
private int port;
public static void main(String[] args) {
CommandLine cmd = new CommandLine(new HideOptionParams());
cmd.setHelpFactory(new IHelpFactory() {
public Help create(final CommandSpec commandSpec, ColorScheme colorScheme) {
return new Help(commandSpec, colorScheme) {
#Override
public IOptionRenderer createDefaultOptionRenderer() {
return new IOptionRenderer() {
public Text[][] render(OptionSpec option,
IParamLabelRenderer ignored,
ColorScheme scheme) {
return makeOptionList(option, scheme);
}
};
}
};
}
});
cmd.usage(System.out);
}
private static Text[][] makeOptionList(OptionSpec option, ColorScheme scheme) {
String shortOption = option.shortestName(); // assumes every option has a short option
String longOption = option.longestName(); // assumes every option has a short and a long option
if (option.negatable()) { // ok to omit if you don't have negatable options
INegatableOptionTransformer transformer =
option.command().negatableOptionTransformer();
shortOption = transformer.makeSynopsis(shortOption, option.command());
longOption = transformer.makeSynopsis(longOption, option.command());
}
// assume one line of description text (may contain embedded %n line separators)
String[] description = option.description();
Text[] descriptionFirstLines = scheme.text(description[0]).splitLines();
Text EMPTY = Ansi.OFF.text("");
List<Text[]> result = new ArrayList<Text[]>();
result.add(new Text[]{
scheme.optionText(String.valueOf(
option.command().usageMessage().requiredOptionMarker())),
scheme.optionText(shortOption),
scheme.text(","), // we assume every option has a short and a long name
scheme.optionText(longOption), // just the option name without parameter
descriptionFirstLines[0]});
for (int i = 1; i < descriptionFirstLines.length; i++) {
result.add(new Text[]{EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i]});
}
// if #Command(showDefaultValues = true) was set, append line with default value
if (option.command().usageMessage().showDefaultValues()) {
Text defaultValue = scheme.text(" Default: " + option.defaultValueString(true));
result.add(new Text[]{EMPTY, EMPTY, EMPTY, EMPTY, defaultValue});
}
return result.toArray(new Text[result.size()][]);
}
}
This shows the following usage help message:
Usage: <main class> [-p] [-o=<port>] [-u=<user>]
-o, --port Listening port, default is 12345.
-p, --password Password for the user.
-u, --user The connecting user name.
Note that the parameter label is omitted in the options list, but is still shown in the synopsis. If you do not want any parameter labels shown in the synopsis, you can specify a custom synopsis in the #Command annotation, see this section in the user manual.

Xamarin.Forms activate/deactivate toolbar items not working

I have a Xamarin.Form MainPage:ContentPage with a ToolbarItems Bar on top. The toolbar items are bound to my ViewModel like so:
<ToolbarItem Text="Sync" Command="{Binding ReloadCommand}" >
</ToolbarItem>
The availability of the Item depends on some logic:
private bool canReloadExecute(object arg)
{
bool result = (!IsReloading && (App.GetPersistentSetting("DeviceID") != "") && (App.GetPersistentSetting("BuildingID") != ""));
return result;
}
There is a separate dialog controlling the DeviceID and BuildingID on a different settings page. Once any of those ids is entered it is persistently stored away
App.SetPersistentSetting("DeviceID",value);
Problem is, that the menu items don't change their appearance once my code uses popAsync() to return to the Main page. I need to restart my app to see the changes. According to the debugger, canReloadExecute isn't called. Why this?
What I tried to work around this issue is to force a refresh in the MainPage's OnAppearing method like this:
public void RefreshToolbarItems()
{
TestApp.ViewModels.MainViewModel mvm = (TestApp.ViewModels.MainViewModel)BindingContext;
mvm.RefreshToolbarItems();
}
... and in the ViewModel:
public void RefreshToolbarItems()
{
OnPropertyChanged("BuildingScanCommand");
OnPropertyChanged("ReloadCommand");
}
but this code runs through but changes nothing, while the Debugger shows that the routine is indeed firing the events, they seem to go nowhere.
Any ideas how I can get my menu going?
Edit 1: "Show command initalization"
I am not shre what specifically you mean, but here is the whole code dealing with the command:
private ICommand _reloadCommand;
public ICommand ReloadCommand => _reloadCommand ?? (_reloadCommand = new Command(ExecuteReloadCommand, canReloadExecute));
private bool _isReloading = false;
public bool IsReloading
{
get => _isReloading;
set
{
_isReloading = value;
((Command)_reloadCommand).ChangeCanExecute();
OnPropertyChanged(nameof(ReloadCommand));
}
}
private bool canReloadExecute(object arg)
{
bool result = (!IsReloading && (App.GetPersistentSetting("DeviceID") != "") && (App.GetPersistentSetting("BuildingID") != ""));
return result;
}
private async void ExecuteReloadCommand(object obj)
{
IsReloading = true;
// Some code ...
IsReloading = false;
}
The goal is to disable the command, if either the command handler is already running, or if the configuration of DeviceID and/or BuildingId hasn't been done yet.
The enable/disable does almost work, if I set the DeviceId and BuildingId, and restart the app, the command is properly enabled or disabled. It doesn't work, however, if I set the Ids in a sub-page and return to the main page.
meanwhile I came to the conclusion, that firing onPropertyChange obviously doesn't make the command check its canReloadExecute. So the question is, how do I trigger this?
I finally solved the issue myself, this code works nicely for me:
public void RefreshToolbarItems()
{
((Command)BuildingScanCommand).ChangeCanExecute();
((Command)ReloadCommand).ChangeCanExecute();
}

CodenameOne filter optimization on set of containers

In my app, I have a searchbox which allows users to filter as they type. For some reason I can't get an InfinteProgress to properly display while the filtering is being executed.
Here's my code:
Pass 1
public void renderForumList(){
try{
magnify = mStateMachine.findForumSearchIcon(form);
}catch(NullPointerException ex){
System.out.println("User typed additional character in search term before previous term finished executing");
}
InfiniteProgress infi = new InfiniteProgress();
magnify.getParent().replace(magnify, infi, null);
Display.getInstance().invokeAndBlock(new Runnable() {
#Override
public void run() {
for (int i = 0;i < containerStates.length;i++){
if(containerStates[i] != listItems[i].isVisible()){
listItems[i].setHidden(!containerStates[i]);
listItems[i].setVisible(containerStates[i]);
}
}
Display.getInstance().callSerially(new Runnable() {
#Override
public void run() {
mStateMachine.findForumsListComponent(form).animateLayout(200);
mStateMachine.findContainer2(form).replace(infi, magnify, null);
}
});
}
});
}
In this version, the infinite progress shows up in the proper position, but it doesn't spin.
Pass 2
public void renderForumList(){
try{
magnify = mStateMachine.findForumSearchIcon(form);
}catch(NullPointerException ex){
System.out.println("User typed additional character in search term before previous term finished executing");
}
InfiniteProgress infi = new InfiniteProgress();
magnify.getParent().replace(magnify, infi, null);
for (int i = 0;i < containerStates.length;i++){
if(containerStates[i] != listItems[i].isVisible()){
listItems[i].setHidden(!containerStates[i]);
listItems[i].setVisible(containerStates[i]);
}
}
mStateMachine.findForumsListComponent(form).animateLayout(200);
mStateMachine.findContainer2(form).replace(infi, magnify, null);
}
}
}
In this version, the magnifier icon just flashes briefly, but the InfiniteProgress spinner is never visible.
I get the same results on the simulator and on an Android device.
How can I get the InfiniteProgress to spin while the search is taking place?
invokeAndBlock opens a new thread and thus violates the EDT as you access UI components on a separate thread.
Try using callSerially instead to postpone the following code into the next EDT cycle although I'm not sure that will help as everything is still happening on the EDT.
Alternatively I'm guessing the method isVisible takes time, so you can enclose that call alone in invokeAndBlock.
To understand invokeAndBlock check out the developer guide https://www.codenameone.com/manual/edt.html

Manage wait cursor for task

I'm outside the UI and wish to display a wait cursor while stuff is
happening and using this basic pattern:
on UI - primaryStage.scene.cursor = Cursor.WAIT
try {
do stuff off UI...
} finally {
on UI - primaryStage.scene.cursor = Cursor.DEFAULT
}
While running I can start another process which completes quickly and the Cursor is restored before the first task completes.
I don't mind "waiting" while the first task completes, but I don't think this means doing the work on the UI thread?
Is there any built in solution for this pattern provided in javafx?
My tab contains 2 Combo Box. When I hit the 2nd Combo Box drop down, a WAIT cursor sometimes appears over the list even though the Cursor is currently DEFAULT state. If I move the mouse pointer outside/back on the list the cursor is correctly displayed as Default. Would this be a separate issue or somehow related?
VIEW
label 'From'
comboBox(items: bind(model.wcomboFromItemsProperty()), value: bind(model.wcomboFromProperty()), selectFromAction)
label 'To'
comboBox(items: bind(model.wcomboFromItemsProperty()), value: bind(model.wcomboToProperty()), selectToAction)
MODEL
#FXObservable ListElement wcomboFrom = new ListElement()
#FXObservable ListElement wcomboTo = new ListElement()
#FXObservable List wcomboFromItems = FXCollections.observableArrayList()
#FXObservable List wcomboToItems = FXCollections.observableArrayList()
final ObjectProperty<Cursor> CURSOR_DEFAULT = new SimpleObjectProperty<>(Cursor.DEFAULT)
final ObjectProperty<Cursor> CURSOR_WAIT = new SimpleObjectProperty<>(Cursor.WAIT)
CONTROLLER
//lifecycle
void onReadyStart(GriffonApplication application) {
loadWindowData()
}
// both combo boxes contain the same items
protected void loadWindowData() {
def list = [new ListElement(textValue: '')]
list.addAll dataService.getData().collect {
new ListElement(textValue: it.name, objectValue: it)
}
runInsideUIAsync {
model.wcomboFromItems.addAll(list)
model.wcomboToItems.addAll(list)
}
}
void selectFrom() {
performAction {
gcListFrom = getControlList(model.wcomboFrom.objectValue)
setTreeItems(model.wtreeGcFrom, gcListFrom, model.wcomboFrom)
setTreeItems(model.wtreeGcTo, gcListTo, model.wcomboTo)
}
}
void selectTo() {
performAction {
gcListTo = getControlList(model.wcomboTo.objectValue)
setTreeItems(model.wtreeGcTo, gcListTo, model.wcomboTo)
}
}
def performAction = {c ->
Task<Void> t = new Task() {
#Override protected Void call() {
println "Running closure " + isUIThread()
c.call()
}
}
runInsideUISync {
application.primaryStage.scene.cursorProperty().bind(Bindings.when(t.runningProperty())
.then(model.CURSOR_WAIT).otherwise(model.CURSOR_DEFAULT))
}
runOutsideUI(t)
}
OTHER
#EqualsAndHashCode(includes = 'textValue')
class ListElement implements Serializable {
String textValue = ""
Serializable objectValue // Serializable object from business model
#Override
String toString() {
textValue
}
}
The Griffon framework automatically invokes the onAction controller events outside the UI thread. GroovyFX contains some magic which adds an "onSelect" action bound to selectionModel.selectedItemProperty i.e.
class GroovyFXEnhancer {
static void enhanceClasses() {
...
ComboBox.metaClass {
cellFactory << { Closure closure -> delegate.setCellFactory(closure as Callback)}
onSelect << { Closure closure ->
delegate.selectionModel.selectedItemProperty().addListener(closure as ChangeListener);
}
...
}
}
Is there any built in solution for this pattern provided in javafx?
I would advice you to use the built in Task ;)
It has predefined methods to handle everything you need.
private Task<Void> backgroundTask = new Task() {
#Override
protected Void call() throws Exception {
// Something to do on background thread ;
return null;
}
};
It has a runningProperty(), which can bind to the cursorProperty() of the scene.
You can create two ObjectProperty<Cursor> containing Cursor.DEFAULT and CURSOR.WAIT.
final ObjectProperty<Cursor> CURSOR_DEFAULT = new SimpleObjectProperty<>(Cursor.DEFAULT);
final ObjectProperty<Cursor> CURSOR_WAIT = new SimpleObjectProperty<>(Cursor.WAIT);
Then you can bind them to the task :
scene.cursorProperty().bind(Bindings.when(backgroundTask.runningProperty())
.then(CURSOR_WAIT).otherwise(CURSOR_DEFAULT));
Would this be a separate issue or somehow related?
If your action on the ComboBox is somehow invoking the background thread, then it might be related, else it is difficult to comment.
You can also use the griffon-tasks-plugin http://griffon-plugins.github.io/griffon-tasks-plugin/
This plugin delivers and UI toolkit agnostik SwingWorker-like API for executing tasks in a background thread.

how to update Visual Studio UI when using DynamicItemStart inside a vsix package

I'm implementing a DynamicItemStart button inside a Menu Controller. I'm loading the dynamic items for this button when Visual Studio starts. Everything is loaded correctly so the initialize method is called an I see all the new items in this Dynamic button. After the package is completely loaded I want to add more items to this Dynamic button, but since the package is already loaded the initialize method is not called again and I cannot see the new items in this Dynamic button. I only see the ones that were loaded when VS started.
Is there any way that I can force the update of this Dynamic button so it shows the new items?. I want to be able to update the VS UI after I added more items but outside the Initialize method.
The implementation I did is very similar to the one showed on this msdn example:
http://msdn.microsoft.com/en-us/library/bb166492.aspx
Does anyone know if an Update of the UI can be done by demand?
Any hints are greatly appreciated.
I finally got this working. The main thing is the implementation of a derived class of OleMenuCommand that implements a new constructor with a Predicate. This predicate is used to check if a new command is a match within the DynamicItemStart button.
public class DynamicItemMenuCommand : OleMenuCommand
{
private Predicate<int> matches;
public DynamicItemMenuCommand(CommandID rootId, Predicate<int> matches, EventHandler invokeHandler, EventHandler beforeQueryStatusHandler)
: base(invokeHandler, null, beforeQueryStatusHandler, rootId)
{
if (matches == null)
{
throw new ArgumentNullException("Matches predicate cannot be null.");
}
this.matches = matches;
}
public override bool DynamicItemMatch(int cmdId)
{
if (this.matches(cmdId))
{
this.MatchedCommandId = cmdId;
return true;
}
this.MatchedCommandId = 0;
return false;
}
}
The above class should be used when adding the commands on execution time. Here's the code that creates the commands
public class ListMenu
{
private int _baselistID = (int)PkgCmdIDList.cmdidMRUList;
private List<IVsDataExplorerConnection> _connectionsList;
public ListMenu(ref OleMenuCommandService mcs)
{
InitMRUMenu(ref mcs);
}
internal void InitMRUMenu(ref OleMenuCommandService mcs)
{
if (mcs != null)
{
//_baselistID has the guid value of the DynamicStartItem
CommandID dynamicItemRootId = new CommandID(GuidList.guidIDEToolbarCmdSet, _baselistID);
DynamicItemMenuCommand dynamicMenuCommand = new DynamicItemMenuCommand(dynamicItemRootId, isValidDynamicItem, OnInvokedDynamicItem, OnBeforeQueryStatusDynamicItem);
mcs.AddCommand(dynamicMenuCommand);
}
}
private bool IsValidDynamicItem(int commandId)
{
return ((commandId - _baselistID) < connectionsCount); // here is the place to put the criteria to add a new command to the dynamic button
}
private void OnInvokedDynamicItem(object sender, EventArgs args)
{
DynamicItemMenuCommand invokedCommand = (DynamicItemMenuCommand)sender;
if (null != invokedCommand)
{
.....
}
}
private void OnBeforeQueryStatusDynamicItem(object sender, EventArgs args)
{
DynamicItemMenuCommand matchedCommand = (DynamicItemMenuCommand)sender;
bool isRootItem = (matchedCommand.MatchedCommandId == 0);
matchedCommand.Enabled = true;
matchedCommand.Visible = true;
int indexForDisplay = (isRootItem ? 0 : (matchedCommand.MatchedCommandId - _baselistID));
matchedCommand.Text = "Text for the command";
matchedCommand.MatchedCommandId = 0;
}
}
I had to review a lot of documentation since it was not very clear how the commands can be added on execution time. So I hope this save some time whoever has to implement anything similar.
The missing piece for me was figuring out how to control the addition of new items.
It took me some time to figure out that the matches predicate (the IsValidDynamicItem method in the sample) controls how many items get added - as long as it returns true, the OnBeforeQueryStatusDynamicItem gets invoked and can set the details (Enabled/Visible/Checked/Text etc.) of the match to be added to the menu.

Resources