JavaFX: How to create an undo point on a codeArea - javafx

I have a CodeArea (org.fxmisc.richtext.CodeArea). It support the hotkeys CTRL-Z for undo and CTRL-Y for redo.
I am inserting a text programmatically at the caret position.
Now when I hit undo, this undo goes further than undoing the text insertion, it undoes the creation of the file so that the code area is empty again.
I would like to create an undo save point before I insert the text.
There must be some way to do this (I hope!).
public void insertText(String text)
{
//TODO insert code here to create an undo point
int index = codeArea.getCaretPosition();
codeArea.insertText(index, text);
}

Use the UndoManager:
public void insertText(String text)
{
codeArea.getUndoManager().mark();
int index = codeArea.getCaretPosition();
codeArea.insertText(index, text);
}

Related

Xamarin Forms Entry boxes loses their cursor position with custom keypad

I am attempting to create a calculator app with a custom keypad using the MVVM pattern. The calculator has four entry boxes and I am suppressing the phone's keyboard from showing by using a custom renderer. I have noticed that the entrees lose their cursor position when I type numbers in an entry, change the cursor position manually by tapping in another position, and start typing again. When I start typing again, the initial character goes into the correct position, but any characters after that goes at the beginning of the string which means the cursor position is zero.
I cannot figure out what is resetting the cursor position. I am keeping track of the cursor position through binding. Here is a small snippet from my code below. So if EntryOne is Selected(Has Focus) and you start typing, the GetText method is called and I am passing in the cursor position by reference. The text that already exists in the Entry is separated into two parts. All the characters in front of the cursor position are part one and all the characters after the cursor position is part two. The parameter is the number the user pressed. All three strings are concatenated together to display the new text in the Entry box. If I use the phone’s keyboard I do not have this issue. So I know it is possible.
Please see the app attached and let me know if more info is needed. Any help would be greatly appreciated.
Thank you in advance!!!
EntryOneText = GetText(EntryOneText, parameter, ref _entryOneCursorIndex);
private string GetText(string text, string parameter, ref int cursorPosition)
{
if (!string.IsNullOrEmpty(text))
{
string partOne = text.Substring(0, cursorPosition);
string partTwo = text.Substring(cursorPosition, (text.Length - cursorPosition));
cursorPosition++;
return string.Format("{0}{1}{2}", partOne, parameter, partTwo);
}
cursorPosition++;
return parameter;
}
EntryCursorPositionTest
Thanks to Alessandro Caliaro. He provided an answer for me on the Xamarin Forms Forum.
private void EntryOne_Focused(object sender, FocusEventArgs e)
{
_mainViewModel.SelectedEntry = 1;
_mainViewModel.EntryOneCursorIndex = ((Entry)sender).CursorPosition;
}
public ICommand NumericCommand
{
get
{
return new Command<string>((string parameter) =>
{
if (!string.IsNullOrEmpty(parameter))
{
switch (SelectedEntry)
{
case 1:
if (EntryOneText == null)
EntryOneText = "";
int save = EntryOneCursorIndex;
EntryOneText = EntryOneText.Insert(save, parameter);
EntryOneCursorIndex = save + 1;
//EntryOneText = GetText(EntryOneText, parameter, ref _entryOneCursorIndex);
break;

Update QMessageBox continuously within specific function in Qt

I have a program which when it runs, at first the user is asked to initialize the system. In that question form, there are 3 checkboxes that the user can check them for specific person or every persons and the system initializes the items related to that checkbox for the person(s).
When a checkbox is selected, a specific function and subsequently the specific class is called and initialization is done.
In the mainwindow.cpp I have:
InitializeDialog *id=new InitializeDialog;
connect(id,&InitializeDialog::initializeSignal,this,&MainWindow::initializeSlot);
id->exec();
id is the question form which has 3 checkboxes in it. And:
void MainWindow::initializeSlot(QStringList persons, bool interests, bool plots, bool graphs)
{
initializeMBox->setWindowTitle(tr("Initializing System")+"...");
initializeMBox->setText(tr("Please wait until initialization has been done") + ".<br>");
initializeMBox->show();
initializeMBox->setStandardButtons(0);
if (interests)//checkbox 1 is checked
initializeInterests(persons);
if (plots)//checkbox 2 is checked
initializePlots(persons);
if(graphs)//checkbox 3 is checked
initializeGraphs(persons);
initializeMBox->setStandardButtons(QMessageBox::Ok);
}
And again:
void MainWindow::initializeInterests(QStringList persons)
{
for(int p=0;p<persons_comboBox_->count();p++)
{
persons_comboBox_->setCurrentIndex(p);
if (persons.contains(persons_comboBox_->currentText()))
{
//..
//create a specific class object and some specific functions
//..
//*
initializeMBox->setText(initializeMBox->text() + "<div><img src=\":/tickIcon.png\" height=\"10\" width=\"10\">" + " " + tr("Interests analyzed for the persons") + ": " + persons_comboBox_->currentText() + ".</div>");
}
}
}
initializePlots and initializeGraphs are similiar to initializeInterests.
The problem starts from here:
I want to show a message after initialization for every person (as I mentioned by star in initializeInterests) but my initializeMBox (is a QMessageBox) does not show the message continuously and when all persons are initialized, all messages are shown suddenly. It should be noted that I see my initializeMBox is getting bigger but it seems that my QMessageBox is Freezed.
I can't use QtConcurrent::run because my QMessageBox is updated from mainwindow (and so from the base thread) by the line that I mentioned by star.
How can I have a QMessageBox which be updated continuously?
Don't reenter the event loop. Replace id->exec() with id->show(). Manage the dialog's lifetime - perhaps it shouldn't be dynamically created at all.
Don't block in initializeInterests. Instead of changing the combo box, get its data, send it out to an async job, set everything up there, then send the results back.
Pass containers by const reference, not value.
Don't create strings by concatenation.
If the input persons list is long, sort it to speed up look-ups.
For example:
class StringSignal : public QObject {
Q_OBJECT
public:
Q_SIGNAL void signal(const QString &);
};
void MainWindow::initializeInterests(const QStringList &personsIn) {
auto in = personsIn;
std::sort(in.begin(), in.end());
QStringList persons;
persons.reserve(in.size());
for (int i = 0; i < persons_comboBox_->count(); ++i) {
auto const combo = persons_comboBox->itemText(i);
if (std::binary_search(in.begin(), in.end(), combo))
persons << combo;
}
QtConcurrent::run([persons = std::move(persons), w = this](){
StringSignal source;
connect(&source, &StringSignal::signal, w, [w](const QString & person){
w->initalizeMBox->setText(
QStringLiteral("%1 <div><img src=...> %2: %3.</div>")
.arg(w->initalizeMBox->text())
.arg(tr("Interests analyzed for the person"))
.arg(person)
);
});
for (auto &person : persons) { // persons is const
// create a specific object etc.
QThread::sleep(1); // let's pretend we work hard here
source.signal(person);
}
});
}
The creation of the "specific objects" you allude to should not access anything in the gui thread. If it doesn't - pass a copy of the required data, or access it in a thread-safe manner. Sometimes it makes sense, instead of copying the data, move it into the worker, and then when the worker is done - move it back into the gui, by the way of a lambda.

Allow user to copy data from TableView

I have a simple JavaFX app that allows the user to query a database and see the data in a table.
I'd like to allow the user to be able to click a table cell and copy text from that cell to the clipboard with the standard clipboard key stroke: ctrl-c for Win/Linux or cmd-c for Mac. FYI, the text entry controls support basic copy/paste by default.
I'm using the standard javafx.scene.control.TableView class. Is there a simple way to enable cell copy? I did some searches and I see other people create custom menu commands... I don't want to create a custom menu, I just want basic keyboard copy to work with single cells.
I'm using single selection mode, but I can change to something else if need be:
TableView<Document> tableView = new TableView<Document>();
tableView.getSelectionModel().setCellSelectionEnabled(true);
tableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
You just have to create a listener in the scene, something like:
scene.getAccelerators()
.put(new KeyCodeCombination(KeyCode.C, KeyCombination.CONTROL_ANY), new Runnable() {
#Override
public void run() {
int row = table.getSelectionModel().getSelectedIndex();
DataRow tmp = table.getItems().get(row);
final Clipboard clipboard = Clipboard.getSystemClipboard();
final ClipboardContent content = new ClipboardContent();
if(table.getSelectionModel().isSelected(row, numColumn)){
System.out.println(tmp.getNumSlices());
content.putString(tmp.getNumSlices().toString());
}
else{
System.out.println(tmp.getSelected());
content.putString(tmp.getSelected());
}
clipboard.setContent(content);
}
});
For a complete example, you can download it at the gist.
I recommended that you review this post, work for me
http://respostas.guj.com.br/47439-habilitar-copypaste-tableview-funcionando-duvida-editar-funcionalidade
The author use an aditional util java class for enable the cell content copy from a tableView

Axapta: Update FormTreeControl after image change

In my other methods (data, text, etc.) the setItem method works fine to display changes made to a tree item. However, calling setItem after changing an item's icon doesn't seem to have any effect. What is the best way to update the tree item so the new icon appears?
Thanks
public void modified()
{
FormTreeItem workingItem;
;
super();
//find the current item
workingItem = FormTreeControl.getItem(FormTreeControl.getSelection());
//update the value
workingItem.Image(1);
//update the item in the list
FormTreeControl.setItem(workingItem);
}
Found a couple of issues here:
1. Never found a way to update the icon on a tree item effectively.
2. Found out some of the tree control objects aren't initialized if you try to add/delete from a datasource method, so deleting items throws Object Not Initialized errors.
Fixed it by:
1. Create a new item (addAfterIdx of the old item).
2. Delete the old item.
3. Select the new item.
3. Move the method from the datasource to the actual form control.
Here's the code that worked for me:
public boolean modified()
{
boolean ret;
FormTreeItem workingItem = FormTreeControl.getItem(currentEditingIdx);
TreeItemIdx newItemIdx;
;
ret = super();
//create a new item
newItemIdx = SysFormTreeControl::addTreeItem(FormTreeControl, workingItem.text(), FormTreeControl.getParent(workingItem.idx()), workingItem.data(), element.imageIdx(ABC_Icon.text()));
//delete the old item
FormTreeControl.delete(currentEditingIdx);
//select the new item
FormTreeControl.selectionChanged(FormTreeControl.getItem(FormTreeControl.getRoot()), FormTreeControl.getItem(newItemIdx), FormTreeSelect::Unknown);
return ret;
}

TreeView manipulation, saving adding etc

Here is what I am trying to do. I have a TreeView server side control (asp.net 2.0) and I need the user to be able to add nodes to it, then after all the nodes desired are added, the data should be saved to the database.
Here are some things I would like to pay attention to:
1) I don't want to save the tree data each time the new node is added, but rather keep the data in session until the user decides to save the entire tree. The question here is: can I bind the tree to ArrayList object and keep that object in session (rather than keeping the whole tree in session)? Then each time the node is added I will have to rebind the tree to the ArrayList rather than database.
2) I wish to minimize ViewState, any tips? What works best: compressing viewstate or keeping it all on the server at all times?
Thanks!
Use TreeNodeCollection as your internal array to hold in either ViewState or Session. Here's a rough mock-up of an approach you can use; far from perfect, but should set you on the right track.
TreeView tv = new TreeView();
// Button click event for 'Add Node' button
protected void AddNode(object sender, EventArgs e)
{
if (SaveNodeToDb(txtNewNode.Text, txtNavUrl.Text))
{
// Store user input details for new node in Session
Nodes.Add(new TreeNode() { Text = txtNewNode.Text, NavigateUrl = txtNavUrl.Text });
// Clear and re-add
tv.Nodes.Clear();
foreach (TreeNode n in Nodes)
tv.Nodes.Add(n);
}
}
public bool SaveNodeToDb(string name, string url)
{
// DB save action here.
}
public TreeNodeCollection Nodes
{
get
{
if (Session["UserNodes"] ! = null)
return (TreeNodeCollection) Session["UserNodes"];
else
return new TreeNodeCollection();
}
set
{
Session["UserNodes"] = value;
}
}

Resources