Dynamics AX 2012 Only One Copy of a Form Open - forms

Anyone have any tips/code snippets for preventing more than one copy of a custom X++ form from being opened at a time?
Best case: Attempt to open another copy of the form, and the original gains focus
Acceptable: User receives a notice that the form is already open

you could insert the code below into the form's init method.
If you have any questions to the code don't hesitate to ask!
public void init()
{
#define.CACHE_OWNER ('MyForm')
#define.CACHE_KEY_INSTANCE ('Instance')
FormRun existingForm()
{
;
if (infolog.globalCache().isSet(#CACHE_OWNER, #CACHE_KEY_INSTANCE))
{
return infolog.globalCache().get(
#CACHE_OWNER, #CACHE_KEY_INSTANCE);
}
return null;
}
void registerThisForm()
{
;
infolog.globalCache().set(#CACHE_OWNER, #CACHE_KEY_INSTANCE, this);
}
boolean isAlreadyOpened()
{
;
return existingForm() ? !existingForm().closed() : false;
}
void activateExistingForm()
{
;
existingForm().activate(true);
}
;
super();
if (isAlreadyOpened())
{
activateExistingForm();
this.close();
}
else
{
registerThisForm();
}
}

Add the following code to the init method of the form as follows. No other changes are required.
public void init()
{
#define.CACHE_OWNER('MyForm')
int hWnd;
super();
if (infolog.globalCache().isSet(#CACHE_OWNER, curUserId()))
{
hWnd = infolog.globalCache().get(#CACHE_OWNER, curUserId());
}
if (WinApi::isWindow(hWnd))
{
element.closeCancel();
WinAPI::bringWindowToTop(hWnd);
}
else
{
infolog.globalCache().set(#CACHE_OWNER, curUserId(), element.hWnd());
}
}

Related

Eclipse EditorPart save on partDeactivated

My problem is that I have a custom application, using EditorParts, which are persisted to a database. The user can open several Editors, and switch between them. I need to ask the user to save any unsaved changes in an Editor, before switching to the next Editor (or else close it).
I have created an IPartListener2, and I receive the partDeactivated notification. If isDirty()==true, I bring up a MessageDialog asking to save or not; because I want to call editor.doSave().
My problem is that does not work. I never see the MessageDialog, because another partDeactivated fires. I guess, this is caused by the MessageDialog over the Editor.
I have researched How to listen to lose focus event of a part in Eclipse E4 RCP?, but that did not help me.
thanks to help a e4 beginner
public class DatasetAttachmentEditor {
... // code here
#Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
... // code here
site.getPage().addPartListener(new EditorsPartListener(this));
}
}
public class EditorsPartListener implements IPartListener2 {
private IEditorPart editor;
public EditorsPartListener(IEditorPart editor) {
this.editor = editor;
}
#Override
public void partClosed(IWorkbenchPartReference partRef) {
if (partRef.getPage().getActiveEditor().getClass().getName().equals(editor.getClass().getName())) {
partRef.getPage().removePartListener(this);
}
}
#Override
public void partDeactivated(IWorkbenchPartReference partRef) {
if (!partRef.getClass().getName().equals("org.eclipse.ui.internal.EditorReference")) {
System.out.println("partDeactivated: not a Editor="+partRef.getClass().getName());
return;
}
if (!editor.isDirty()) {
// if the editor is not dirty - do nothing
return;
}
// ask if to save
int choice = EditorPartSaveDialog(partRef.getPage().getActiveEditor());
if(choice == MessageDialog.OK) {
// save the Editor
try {
ProgressMonitorDialog progress = new ProgressMonitorDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
progress.setCancelable(false);
progress.run(false, false, new IRunnableWithProgress() {
#Override
public void run(IProgressMonitor monitor) {
// do the save
editor.doSave(monitor);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
else {
// don't save: just close it
partRef.getPage().closeEditor(editor, false);
}
}
#Override
public void partActivated(IWorkbenchPartReference partRef) {
}
#Override
public void partBroughtToTop(IWorkbenchPartReference partRef) {
}
#Override
public void partOpened(IWorkbenchPartReference partRef) {
}
#Override
public void partHidden(IWorkbenchPartReference partRef) {
}
#Override
public void partVisible(IWorkbenchPartReference partRef) {
}
#Override
public void partInputChanged(IWorkbenchPartReference partRef) {
}
/**
* Asks the user to Save changes
* #param editor
* #return MessageDialog.OK to save, MessageDialog.CANCEL otherwise
*/
private int EditorPartSaveDialog(IEditorPart editor) {
// If save confirmation is required ..
String message = NLS.bind("''{0}'' has been modified. Save changes?", LegacyActionTools.escapeMnemonics(editor.getTitle()));
// Show a dialog.
MessageDialog d = new MessageDialog(
Display.getCurrent().getActiveShell(),
"Save Editor", null, message,
MessageDialog.QUESTION,
0,
"Save",// MessageDialog 0x0 (OK)
"Don't Save: close"// MessageDialog 0x1 (CANCEL)
)
return d.open();
}
}
You probably need to run your code after the deactivate event has finished. You can do this using Display.asyncExec.
Something like:
#Override
public void partDeactivated(IWorkbenchPartReference partRef) {
if (!partRef.getClass().getName().equals("org.eclipse.ui.internal.EditorReference")) {
System.out.println("partDeactivated: not a Editor="+partRef.getClass().getName());
return;
}
if (!editor.isDirty()) {
// if the editor is not dirty - do nothing
return;
}
Display.getDefault().asyncExec(() ->
{
// TODO the rest of your deactivate code goes here
});
}
(Above code assumes you are using Java 8 or later)
This is 3.x compatibility mode code, not e4.
I have found a great solution, using the suggestions above and Enumerating all my Eclipse editors?
I am checking all editors first, then all persisted editors - skipping itself and the persisted objects.
Thanks for your comments!
public class ConceptAcronymValidator implements IValidator {
private ConceptInstanceEditor myEditor;
public ConceptAcronymValidator(ConceptInstanceEditor editor) {
super();
this.myEditor = editor;
}
#Override
public IStatus validate(Object value) {
// check all Editors
for (IEditorReference editorRef: PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getEditorReferences()) {
IEditorPart editor = editorRef.getEditor(false);
if (editor != null) {
// don't check our own Editor
if (!editor.equals(myEditor)) {
ConceptInstanceEditor conceptEditor = (ConceptInstanceEditor)editor;
if (conceptEditor.getTxtAcronym().equals(value.toString())) {
return ValidationStatus.error("This Concept is already used by Editor <"+
conceptEditor.getConceptModel().getName().getValue(MultilingualString.EN)+
">");
}
}
}
}
// check all persisted Concepts
List<Concept> concepts = ReferenceServiceFactory.getService().getConcepts();
for (Concept concept: concepts) {
Concept myConcept = (Concept) myEditor.getConceptModel().getInstance();
// check if a new Editor
if (myConcept == null) {
if (concept.getAcronym().equals(value.toString())) {
return ValidationStatus.error("This Concept is already used by <"+
concept.getName().getValue(MultilingualString.EN)+
">");
}
}
else {
// don't check own Instance
if (!concept.equals(myConcept)) {
if (concept.getAcronym().equals(value.toString())) {
return ValidationStatus.error("This Concept is already used by <"+
concept.getName().getValue(MultilingualString.EN)+
">");
}
}
}
}
return Status.OK_STATUS;
}
}

GWT Drag and Drop File Upload not working

So I have implemented a very simple drag and drop file upload widget. Basically my widget is a vertical panel with a couple of labels and a button inside. The user can either drag file into vertical panel or click button and browse for file.
My problem is that when I drag a file into the vertical panel it fires the DragLeaveEvent every time I drag the item over the space that the labels or button occupies. I want it to know that the item is in the vertical panel even when it is on top of the label or button. Im sure I am missing something simple. I provide the drag functionality by adding these dom handlers to the vertical panel:
addDomHandler(new DragEnterHandler() {
#Override
public void onDragEnter(DragEnterEvent event) {
System.out.println("drag enter");
highlight(true);
}
}, DragEnterEvent.getType());
addDomHandler(new DragLeaveHandler() {
#Override
public void onDragLeave(DragLeaveEvent event) {
System.out.println("drag leave");
highlight(false);
}
}, DragLeaveEvent.getType());
addDomHandler(new DragOverHandler() {
#Override
public void onDragOver(DragOverEvent event) {
}
}, DragOverEvent.getType());
addDomHandler(new DropHandler() {
#Override
public void onDrop(DropEvent event) {
System.out.println("drop");
// stop default behaviour
event.preventDefault();
event.stopPropagation();
// starts the fetching, reading and callbacks
if (fileUploadHandler != null) {
handleFiles(event.getDataTransfer(), fileUploadHandler);
}
highlight(false);
}
}, DropEvent.getType());
Check that the event target is a child (or grand child) of your panel, or in this case maybe rather whether the event target is exactly your panel's element:
if (verticalPanel.getElement().isOrHasChild(Node.as(event.getNativeEvent().getEventTarget()))) {
// within the panel (possibly on a child)
}
if (verticalPanel.getElement() == Node.as(event.getNativeEvent().getEventTarget())) {
// targetting exactly the panel (e.g. leaving the panel, not one of its children)
}
Through lots of research I have come to the only solution I could find. I set highlight to true in the dragover handler instead of drag enter.
panel.addDomHandler(new DragEnterHandler() {
#Override
public void onDragEnter(DragEnterEvent event) {
}
}, DragEnterEvent.getType());
panel.addDomHandler(new DragLeaveHandler() {
#Override
public void onDragLeave(DragLeaveEvent event) {
highlight(false);
}
}, DragLeaveEvent.getType());
panel.addDomHandler(new DragOverHandler() {
#Override
public void onDragOver(DragOverEvent event) {
highlight(true);
}
}, DragOverEvent.getType());
panel.addDomHandler(new DropHandler() {
#Override
public void onDrop(DropEvent event) {
// stop default behaviour
event.preventDefault();
event.stopPropagation();
// starts the fetching, reading and callbacks
handleFiles(event.getDataTransfer());
highlight(false);
}
}, DropEvent.getType());
I copy pasted your code, but also added a:
RootPanel.get().addHandler(dropHandler, DropEvent.getType());
My drophandler looks like this:
DropHandler dropHandler = new DropHandler() {
#Override
public void onDrop(DropEvent event) {
handleFiles(event.getDataTransfer(), new FileUploadHandler() {
#Override
public TYPE specifyFileType() {
return TYPE.BINARY;
}
#Override
public void handleFileContent(String fileName, String fileContent) {
// do stuff with filename and content
}
#Override
public boolean checkFileName(String fileName) {
return true;
}
});
event.preventDefault();
event.stopPropagation();
}
};
and the file-upload interface:
public interface FileUploadHandler {
static public enum TYPE {
TEXT, BINARY, DATAURL
};
// check the filename and extension and return true if you are happy with
// proceeding
// returnning false will prevent the file from being read
boolean checkFileName(String fileName);
// tell the method to use to read this file
TYPE specifyFileType();
// do your stuff here, eg upload to a server
void handleFileContent(String fileName, String fileContent);
}
and the handle files func: (note you will have to change classpath to the FileUploadHandler-interface)
// native method to make use of the HTML5 file API functionality
private final native void handleFiles(JavaScriptObject dataTransfer, FileUploadHandler fileUploadHandler) /*-{
var files = dataTransfer.files;
var i;
var file;
var reader = new FileReader();
for (i = 0; i < files.length; i++) {
file = files[i];
if (fileUploadHandler.#<classpath_to>.FileUploadHandler::checkFileName(Ljava/lang/String;)(file.name)) {
var type = fileUploadHandler.#<classpath_to>.FileUploadHandler::specifyFileType()();
reader.onload = function(e) {
fileUploadHandler.#<classpath_to>.FileUploadHandler::handleFileContent(Ljava/lang/String;Ljava/lang/String;)(file.name, e.target.result);
}
if (type == "TEXT") {
reader.readAsText(file);
} else if (type == "BINARY") {
reader.readAsBinaryString(file);
} else if (type == "DATAURL") {
reader.readAsDataURL(file);
// not supported
} else if (type == "ARRAYBUFFER") {
reader.readAsArrayBuffer(file);
} else {
}
}
}
}-*/;

GEF + EMF: Why doesn't my editor remove the Figure for a removed object when refreshChildren() is called?

I have implemented a GEF editor for a graph-like EMF model, with a remove command for a certain type of node in the graph. I think I've done all the necessary steps in order to make this set up work (vainolo's blog has been a great help).
However, when I'm deleting a model element, the view doesn't get refreshed, i.e., the figure for the model element isn't removed from the editor view, and I have no idea why. I'd be extremely grateful if somebody could have a look at my sources and point me to any problems (and possibly solutions :)). Many thanks in advance!
Below are what I think are the important classes for this issue. Please do let me know should I add further code/edit the code, etc. (I've left out code that I thought doesn't help, e.g., getters and setters, class variables). Thanks!
DiagramEditPart
public class DiagramEditPart extends AbstractGraphicalEditPart {
public DiagramEditPart(Diagram model) {
this.setModel(model);
adapter = new DiagramAdapter();
}
#Override protected IFigure createFigure() {
Figure figure = new FreeformLayer();
return figure;
}
#Override protected void createEditPolicies() {
installEditPolicy(EditPolicy.LAYOUT_ROLE, new DiagramXYLayoutPolicy());
}
#Override protected List<EObject> getModelChildren() {
List<EObject> allModelObjects = new ArrayList<EObject>();
if (((Diagram) getModel()).getMyNodes() != null)
allModelObjects.addAll(((Diagram) getModel()).getMyNodes());
return allModelObjects;
}
#Override public void activate() {
if(!isActive()) {
((Diagram) getModel()).eAdapters().add(adapter);
}
super.activate();
}
#Override public void deactivate() {
if(isActive()) {
((Diagram) getModel()).eAdapters().remove(adapter);
}
super.deactivate();
}
public class DiagramAdapter implements Adapter {
#Override public void notifyChanged(Notification notification) {
switch (notification.getEventType()) {
case Notification.REMOVE: refreshChildren();
break;
default:
break;
}
}
#Override public Notifier getTarget() {
return (Diagram) getModel();
}
#Override public void setTarget(Notifier newTarget) {
// Do nothing.
}
#Override public boolean isAdapterForType(Object type) {
return type.equals(Diagram.class);
}
}
}
MyNodeEditPart
public class MyNodeEditPart extends AbstractGraphicalEditPart {
public MyNodeEditPart(MyNode model) {
this.setModel(model);
adapter = new MyNodeAdapter();
}
#Override protected IFigure createFigure() {
return new MyNodeFigure();
}
#Override protected void createEditPolicies() {
installEditPolicy(EditPolicy.COMPONENT_ROLE, new MyNodeComponentEditPolicy());
}
#Override protected void refreshVisuals() {
MyNodeFigure figure = (MyNodeFigure) getFigure();
DiagramEditPart parent = (DiagramEditPart) getParent();
Dimension labelSize = figure.getLabel().getPreferredSize();
Rectangle layout = new Rectangle((getParent().getChildren().indexOf(this) * 50),
(getParent().getChildren().indexOf(this) * 50), (labelSize.width + 20),
(labelSize.height + 20));
parent.setLayoutConstraint(this, figure, layout);
}
public List<Edge> getModelSourceConnections() {
if ((MyNode) getModel() != null && ((MyNode) getModel()).getDiagram() != null) {
ArrayList<Edge> sourceConnections = new ArrayList<Edge>();
for (Edge edge : ((MyNode) getModel()).getDiagram().getOutEdges(((MyNode) getModel()).getId())) {
sourceConnections.add(edge);
}
return sourceConnections;
}
return null;
}
// + the same method for targetconnections
#Override public void activate() {
if (!isActive()) {
((MyNode) getModel()).eAdapters().add(adapter);
}
super.activate();
}
#Override public void deactivate() {
if (isActive()) {
((MyNode) getModel()).eAdapters().remove(adapter);
}
super.deactivate();
}
public class MyNodeAdapter implements Adapter {
#Override
public void notifyChanged(Notification notification) {
refreshVisuals();
}
#Override
public Notifier getTarget() {
return (MyNode) getModel();
}
#Override
public void setTarget(Notifier newTarget) {
// Do nothing
}
#Override
public boolean isAdapterForType(Object type) {
return type.equals(MyNode.class);
}
}
}
MyNodeComponentEditPolicy
public class MyNodeComponentEditPolicy extends ComponentEditPolicy {
#Override
protected Command createDeleteCommand(GroupRequest deleteRequest) {
DeleteMyNodeCommand nodeDeleteCommand = new DeleteMyNodeCommand((MyNode) getHost().getModel());
return nodeDeleteCommand;
}
}
DeleteMyNodeCommand
public class DeleteMyNodeCommand extends Command {
public DeleteMyNodeCommand(MyNode model) {
this.node = model;
this.graph = node.getDiagram();
}
#Override public void execute() {
getMyNode().setDiagram(null);
System.out.println("Is the model still present in the graph? " + getGraph().getMyNodes().contains(getMyNode()));
// Returns false, i.e., graph doesn't contain model object at this point!
}
#Override public void undo() {
getMyNode().setDiagram(getGraph());
}
}
EDIT
Re execc's comment: Yes, refreshChildren() is being called. I've tested this by overriding it and adding a simple System.err line, which is being displayed on the console on deletion of a node:
#Override
public void refreshChildren() {
super.refreshChildren();
System.err.println("refreshChildren() IS being called!");
}
EDIT 2
The funny (well...) thing is, when I close the editor and persist the model, then re-open the same file, the node isn't painted anymore, and is not present in the model. But what does this mean? Am I working on a stale model? Or is refreshing/getting the model children not working properly?
EDIT 3
I've just found a peculiar thing, which might explain the isues I have? In the getModelChildren() method I call allModelObjects.addAll(((Diagram) getModel()).getMyNodes());, and getMyNodes() returns an unmodifiable EList. I found out when I tried to do something along the lines of ((Diagram) getModel()).getMyNodes().remove(getMyNode()) in the delete command, and it threw an UnsupportedOperationException... Hm.
EDIT 4
Er, somebody kill me please?
I've double-checked whether I'm handling the same Diagram object at all times, and while doing this I stumbled across a very embarassing thing:
The getModelChildren() method in DiagramEditPart in the last version read approx. like this:
#Override protected List<EObject> getModelChildren() {
List<EObject> allModelObjects = new ArrayList<EObject>();
EList<MyNode> nodes = ((Diagram) getModel()).getMyNodes();
for (MyNode node : nodes) {
if (node.getDiagram() != null); // ### D'Uh! ###
allModelObjects.add(node);
}
return allModelObjects;
}
I'd like to apologize for stealing everyone's time! Your suggestions were very helpful, and indeed helped my to finally track down the bug!
I've also learned a number of lessons, amongst them: Always paste the original code, over-simplifaction may cloak your bugs! And I've learned a lot about EMF, Adapter, and GEF. Still:
There is one semi-colon too many in line 5 of the following part of the code, namely after the if statement: if (node.getDiagram() != null);:
1 #Override protected List<EObject> getModelChildren() {
2 List<EObject> allModelObjects = new ArrayList<EObject>();
3 EList<MyNode> nodes = ((Diagram) getModel()).getMyNodes();
4 for (MyNode node : nodes) {
5 if (node.getDiagram() != null);
6 allModelObjects.add(node);
7 }
8 return allModelObjects;
9 }

How to disable copy/paste from/to EditText

In my application, there is a registration screen, where i do not want the user to be able to copy/paste text into the EditText field. I have set an onLongClickListener on each EditText so that the context menu showing copy/paste/inputmethod and other options does not show up. So the user won't be able to copy/ paste into the Edit fields.
OnLongClickListener mOnLongClickListener = new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
// prevent context menu from being popped up, so that user
// cannot copy/paste from/into any EditText fields.
return true;
}
};
But the problem arises if the user has enabled a third-party keyboard other than the Android default, which may have a button to copy/paste or which may show the same context menu. So how do i disable copy/paste in that scenario ?
Please let me know if there are other ways to copy/paste as well. (and possibly how to disable them)
Any help would be appreciated.
Best method is to use:
etUsername.setLongClickable(false);
If you are using API level 11 or above then you can stop copy,paste,cut and custom context menus from appearing by.
edittext.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
});
Returning false from onCreateActionMode(ActionMode, Menu) will prevent the action mode from being started(Select All, Cut, Copy and Paste actions).
You can do this by disabling the long press of the EditText
To implement it, just add the following line in the xml -
android:longClickable="false"
I am able to disable copy-and-paste functionality with the following:
textField.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
return false;
}
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode actionMode, MenuItem item) {
return false;
}
public void onDestroyActionMode(ActionMode actionMode) {
}
});
textField.setLongClickable(false);
textField.setTextIsSelectable(false);
Hope it works for you ;-)
Kotlin solution:
fun TextView.disableCopyPaste() {
isLongClickable = false
setTextIsSelectable(false)
customSelectionActionModeCallback = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu): Boolean {
return false
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu): Boolean {
return false
}
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem): Boolean {
return false
}
override fun onDestroyActionMode(mode: ActionMode?) {}
}
}
Then you can simply call this method on your TextView:
override fun onCreate() {
priceEditText.disableCopyPaste()
}
here is a best way to disable cut copy paste of editText work in all version
if (android.os.Build.VERSION.SDK_INT < 11) {
editText.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
// TODO Auto-generated method stub
menu.clear();
}
});
} else {
editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
public void onDestroyActionMode(ActionMode mode) {
// TODO Auto-generated method stub
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
public boolean onActionItemClicked(ActionMode mode,
MenuItem item) {
// TODO Auto-generated method stub
return false;
}
});
}
In addition to the setCustomSelectionActionModeCallback, and disabled long-click solutions, it's necessary to prevent the PASTE/REPLACE menus from appearing when the text selection handle is clicked, as per the image below:
The solution lies in preventing PASTE/REPLACE menu from appearing in the show() method of the (non-documented) android.widget.Editor class. Before the menu appears, a check is done to if (!canPaste && !canSuggest) return;. The two methods that are used as the basis to set these variables are both in the EditText class:
isSuggestionsEnabled() is public, and may thus be overridden.
canPaste() is not, and thus must be hidden by introducing a function of the same name in the derived class.
A more complete answer is available here.
If you don't wan't to disable long click because you need to perform some functionality on long click than returning true is a better option to do so.
Your edittext long click will be like this.
edittext.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
// Do Something or Don't
return true;
}
});
As per documentation
Returning "True" will indicate that long click have been handled so no need to perform default operations.
I tested this on API level 16, 22 and 25. Its working fine for me. Hope this will help.
Here is a hack to disable "paste" popup. You have to override EditText method:
#Override
public int getSelectionStart() {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getMethodName().equals("canPaste")) {
return -1;
}
}
return super.getSelectionStart();
}
Similar can be done for the other actions.
I've tested this solution and this works
mSubdomainEditText.setLongClickable(false);
mSubdomainEditText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
});
i added Extension Function in Kotlin language :
fun EditText.disableTextSelection() {
this.setCustomSelectionActionModeCallback(object : android.view.ActionMode.Callback {
override fun onActionItemClicked(mode: android.view.ActionMode?, item: MenuItem?): Boolean {
return false
}
override fun onCreateActionMode(mode: android.view.ActionMode?, menu: Menu?): Boolean {
return false
}
override fun onPrepareActionMode(mode: android.view.ActionMode?, menu: Menu?): Boolean {
return false
}
override fun onDestroyActionMode(mode: android.view.ActionMode?) {
}
})
}
you can use it like this :
edit_text.disableTextSelection()
also added below line in your xml :
android:longClickable="false"
android:textIsSelectable="false"
https://github.com/neopixl/PixlUI provides an EditText with a method
myEditText.disableCopyAndPaste().
And it's works on the old API
If you want to disable ActionMode for copy/pasting, you need to override 2 callbacks. This works for both TextView and EditText (or TextInputEditText)
import android.view.ActionMode
fun TextView.disableCopyPaste() {
isLongClickable = false
setTextIsSelectable(false)
customSelectionActionModeCallback = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu) = false
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu) = false
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem) = false
override fun onDestroyActionMode(mode: ActionMode?) {}
}
//disable action mode when edittext gain focus at first
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
customInsertionActionModeCallback = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu) = false
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu) = false
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem) = false
override fun onDestroyActionMode(mode: ActionMode?) {}
}
}
}
This extension is based off above #Alexandr solution and worked fine for me.
#Zain Ali, your answer works on API 11. I just wanted to suggest a way to do in on API 10 as well. Since I had to maintain my project API on that version, I was constantly playing with the functions available in 2.3.3 and got a possibility to do it. I have share the snippet below. I tested the code and it was working for me. I did this snippet on an urgency. Feel free to improve the code if there are any changes that can be done..
// A custom TouchListener is being implemented which will clear out the focus
// and gain the focus for the EditText, in few milliseconds so the selection
// will be cleared and hence the copy paste option wil not pop up.
// the respective EditText should be set with this listener
// tmpEditText.setOnTouchListener(new MyTouchListener(tmpEditText, tmpImm));
public class MyTouchListener implements View.OnTouchListener {
long click = 0;
EditText mEtView;
InputMethodManager imm;
public MyTouchListener(EditText etView, InputMethodManager im) {
mEtView = etView;
imm = im;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
long curr = System.currentTimeMillis();
if (click !=0 && ( curr - click) < 30) {
mEtView.setSelected(false);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mEtView.setSelected(true);
mEtView.requestFocusFromTouch();
imm.showSoftInput(mEtView, InputMethodManager.RESULT_SHOWN);
}
},25);
return true;
}
else {
if (click == 0)
click = curr;
else
click = 0;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mEtView.requestFocusFromTouch();
mEtView.requestFocusFromTouch();
imm.showSoftInput(mEtView, InputMethodManager.RESULT_SHOWN);
}
},25);
return true;
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
mEtView.setSelected(false);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mEtView.setSelected(true);
mEtView.requestFocusFromTouch();
mEtView.requestFocusFromTouch();
imm.showSoftInput(mEtView, InputMethodManager.RESULT_SHOWN);
}
},25);
return true;
}
return false;
}
For smartphone with clipboard, is possible prevent like this.
editText.setFilters(new InputFilter[]{new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (source.length() > 1) {
return "";
} return null;
}
}});
Read the Clipboard, check against the input and the time the input is "typed". If the Clipboard has the same text and it is too fast, delete the pasted input.
the solution is very simple
public class MainActivity extends AppCompatActivity {
EditText et_0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_0 = findViewById(R.id.et_0);
et_0.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
//to keep the text selection capability available ( selection cursor)
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
//to prevent the menu from appearing
menu.clear();
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
}
});
}
}
--------> preview <---------
Try Following custome class for prevant copy and paste in Edittext
public class SegoeUiEditText extends AppCompatEditText {
private final Context context;
#Override
public boolean isSuggestionsEnabled() {
return false;
}
public SegoeUiEditText(Context context) {
super(context);
this.context = context;
init();
}
public SegoeUiEditText(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
public SegoeUiEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
init();
}
private void setFonts(Context context) {
this.setTypeface(Typeface.createFromAsset(context.getAssets(), "Fonts/Helvetica-Normal.ttf"));
}
private void init() {
setTextIsSelectable(false);
this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
this.setLongClickable(false);
}
#Override
public int getSelectionStart() {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getMethodName().equals("canPaste")) {
return -1;
}
}
return super.getSelectionStart();
}
/**
* Prevents the action bar (top horizontal bar with cut, copy, paste, etc.) from appearing
* by intercepting the callback that would cause it to be created, and returning false.
*/
private class ActionModeCallbackInterceptor implements ActionMode.Callback, android.view.ActionMode.Callback {
private final String TAG = SegoeUiEditText.class.getSimpleName();
public boolean onCreateActionMode(ActionMode mode, Menu menu) { return false; }
public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; }
public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return false; }
public void onDestroyActionMode(ActionMode mode) {}
#Override
public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) {
menu.clear();
return false;
}
#Override
public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) {
return false;
}
#Override
public void onDestroyActionMode(android.view.ActionMode mode) {
}
}
}
The solutions above do not take into account pasting with hardware keyboards (Ctrl+v). The easiest solution is to set a TextWatcher on your EditText, and filter characters you want or don't want in the afterTextChanged method. This works for all situations, i.e. typed characters, pastes, auto suggestions and auto corrections.
Rather than completely disabling all actions on the EditText, you may want to prevent only certain actions (like cut/copy, but not paste):
/**
* Prevent copy/cut of the (presumably sensitive) contents of this TextView.
*/
fun TextView.disableCopyCut() {
setCustomSelectionActionModeCallback(
object : Callback {
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?) = false
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
menu?.apply {
removeItem(android.R.id.copy)
removeItem(android.R.id.cut)
}
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?) = false
override fun onDestroyActionMode(mode: ActionMode?) {
// no-op
}
}
)
}
Actions that can be selectively removed:
removeItem(android.R.id.copy)
removeItem(android.R.id.cut)
removeItem(android.R.id.paste)
removeItem(android.R.id.shareText) // Share
removeItem(android.R.id.textAssist) // Open with Chrome
its very late but may it help someone .
add these lines in your edittext xml
android:longClickable="false"
android:textIsSelectable="false"
android:importantForAutofill="no"
I found that when you create an input filter to avoid entry of unwanted characters, pasting such characters into the edit text is having no effect. So this sort of solves my problem as well.
Solution that worked for me was to create custom Edittext and override following method:
public class MyEditText extends EditText {
private int mPreviousCursorPosition;
#Override
protected void onSelectionChanged(int selStart, int selEnd) {
CharSequence text = getText();
if (text != null) {
if (selStart != selEnd) {
setSelection(mPreviousCursorPosition, mPreviousCursorPosition);
return;
}
}
mPreviousCursorPosition = selStart;
super.onSelectionChanged(selStart, selEnd);
}
}
Try to use.
myEditext.setCursorVisible(false);
myEditext.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
public void onDestroyActionMode(ActionMode mode) {
// TODO Auto-generated method stub
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
public boolean onActionItemClicked(ActionMode mode,
MenuItem item) {
// TODO Auto-generated method stub
return false;
}
});
Who is looking for a solution in Kotlin use the below class as a custom widget and use it in the xml.
class SecureEditText : TextInputEditText {
/** This is a replacement method for the base TextView class' method of the same name. This method
* is used in hidden class android.widget.Editor to determine whether the PASTE/REPLACE popup
* appears when triggered from the text insertion handle. Returning false forces this window
* to never appear.
* #return false
*/
override fun isSuggestionsEnabled(): Boolean {
return false
}
override fun getSelectionStart(): Int {
for (element in Thread.currentThread().stackTrace) {
if (element.methodName == "canPaste") {
return -1
}
}
return super.getSelectionStart()
}
public override fun onSelectionChanged(start: Int, end: Int) {
val text = text
if (text != null) {
if (start != text.length || end != text.length) {
setSelection(text.length, text.length)
return
}
}
super.onSelectionChanged(start, end)
}
companion object {
private val EDITTEXT_ATTRIBUTE_COPY_AND_PASTE = "isCopyPasteDisabled"
private val PACKAGE_NAME = "http://schemas.android.com/apk/res-auto"
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
disableCopyAndPaste(context, attrs)
}
/**
* Disable Copy and Paste functionality on EditText
*
* #param context Context object
* #param attrs AttributeSet Object
*/
private fun disableCopyAndPaste(context: Context, attrs: AttributeSet) {
val isDisableCopyAndPaste = attrs.getAttributeBooleanValue(
PACKAGE_NAME,
EDITTEXT_ATTRIBUTE_COPY_AND_PASTE, true
)
if (isDisableCopyAndPaste && !isInEditMode()) {
val inputMethodManager =
context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
this.setLongClickable(false)
this.setOnTouchListener(BlockContextMenuTouchListener(inputMethodManager))
}
}
/**
* Perform Focus Enabling Task to the widget with the help of handler object
* with some delay
* #param inputMethodManager is used to show the key board
*/
private fun performHandlerAction(inputMethodManager: InputMethodManager) {
val postDelayedIntervalTime: Long = 25
Handler().postDelayed(Runnable {
this#SecureEditText.setSelected(true)
this#SecureEditText.requestFocusFromTouch()
inputMethodManager.showSoftInput(
this#SecureEditText,
InputMethodManager.RESULT_SHOWN
)
}, postDelayedIntervalTime)
}
/**
* Class to Block Context Menu on double Tap
* A custom TouchListener is being implemented which will clear out the focus
* and gain the focus for the EditText, in few milliseconds so the selection
* will be cleared and hence the copy paste option wil not pop up.
* the respective EditText should be set with this listener
*
* #param inputMethodManager is used to show the key board
*/
private inner class BlockContextMenuTouchListener internal constructor(private val inputMethodManager: InputMethodManager) :
View.OnTouchListener {
private var lastTapTime: Long = 0
val TIME_INTERVAL_BETWEEN_DOUBLE_TAP = 30
override fun onTouch(v: View, event: MotionEvent): Boolean {
if (event.getAction() === MotionEvent.ACTION_DOWN) {
val currentTapTime = System.currentTimeMillis()
if (lastTapTime != 0L && currentTapTime - lastTapTime < TIME_INTERVAL_BETWEEN_DOUBLE_TAP) {
this#SecureEditText.setSelected(false)
performHandlerAction(inputMethodManager)
return true
} else {
if (lastTapTime == 0L) {
lastTapTime = currentTapTime
} else {
lastTapTime = 0
}
performHandlerAction(inputMethodManager)
return true
}
} else if (event.getAction() === MotionEvent.ACTION_MOVE) {
this#SecureEditText.setSelected(false)
performHandlerAction(inputMethodManager)
}
return false
}
}
}
A widely compatible solution (from Android 1.5 onwards) is
#Override
public boolean onTextContextMenuItem(int id) {
switch (id){
case android.R.id.cut:
onTextCut();
return false;
case android.R.id.paste:
onTextPaste();
return false;
case android.R.id.copy:
onTextCopy();
return false;
}
return true;
}
After spending a lot of time, removing the paste option in ContextMenu of EditText I have followed the below code in Java.
NoMenuEditText.Java
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import androidx.appcompat.widget.AppCompatEditText;
/**
* custom edit text
*/
public class NoMenuEditText extends AppCompatEditText {
private static final String EDITTEXT_ATTRIBUTE_COPY_AND_PASTE = "isCopyPasteDisabled";
private static final String PACKAGE_NAME = "http://schemas.android.com/apk/res-auto";
public NoMenuEditText(Context context) {
super(context);
}
public NoMenuEditText(Context context, AttributeSet attrs) {
super(context, attrs);
EnableDisableCopyAndPaste(context, attrs);
}
/**
* Enable/Disable Copy and Paste functionality on EditText
*
* #param context Context object
* #param attrs AttributeSet Object
*/
private void EnableDisableCopyAndPaste(Context context, AttributeSet attrs) {
boolean isDisableCopyAndPaste = attrs.getAttributeBooleanValue(PACKAGE_NAME,
EDITTEXT_ATTRIBUTE_COPY_AND_PASTE, false);
if (isDisableCopyAndPaste && !isInEditMode()) {
InputMethodManager inputMethodManager = (InputMethodManager)
context.getSystemService(Context.INPUT_METHOD_SERVICE);
this.setLongClickable(false);
this.setOnTouchListener(new BlockContextMenuTouchListener
(inputMethodManager));
}
}
/**
* Perform Focus Enabling Task to the widget with the help of handler object
* with some delay
*/
private void performHandlerAction(final InputMethodManager inputMethodManager) {
int postDelayedIntervalTime = 25;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
NoMenuEditText.this.setSelected(true);
NoMenuEditText.this.requestFocusFromTouch();
inputMethodManager.showSoftInput(NoMenuEditText.this,
InputMethodManager.RESULT_SHOWN);
}
}, postDelayedIntervalTime);
}
/**
* Class to Block Context Menu on double Tap
* A custom TouchListener is being implemented which will clear out the focus
* and gain the focus for the EditText, in few milliseconds so the selection
* will be cleared and hence the copy paste option wil not pop up.
* the respective EditText should be set with this listener
*/
private class BlockContextMenuTouchListener implements View.OnTouchListener {
private static final int TIME_INTERVAL_BETWEEN_DOUBLE_TAP = 30;
private InputMethodManager inputMethodManager;
private long lastTapTime = 0;
BlockContextMenuTouchListener(InputMethodManager inputMethodManager) {
this.inputMethodManager = inputMethodManager;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
long currentTapTime = System.currentTimeMillis();
if (lastTapTime != 0 && (currentTapTime - lastTapTime)
< TIME_INTERVAL_BETWEEN_DOUBLE_TAP) {
NoMenuEditText.this.setSelected(false);
performHandlerAction(inputMethodManager);
return true;
} else {
if (lastTapTime == 0) {
lastTapTime = currentTapTime;
} else {
lastTapTime = 0;
}
performHandlerAction(inputMethodManager);
return true;
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
NoMenuEditText.this.setSelected(false);
performHandlerAction(inputMethodManager);
}
return false;
}
}
#Override
protected void onSelectionChanged(int selStart, int selEnd) {
CharSequence text = getText();
if (text != null) {
if (selStart != text.length() || selEnd != text.length()) {
setSelection(text.length(), text.length());
return;
}
}
super.onSelectionChanged(selStart, selEnd);
}
#Override
public boolean isSuggestionsEnabled() {
return false;
}
#Override
public int getSelectionStart() {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getMethodName().equals("canPaste")) {
return -1;
}
}
return super.getSelectionStart();
}
}
MainActivity
import androidx.appcompat.app.AppCompatActivity;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends AppCompatActivity {
NoMenuEditText edt_username;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edt_username = (NoMenuEditText) findViewById(R.id.edt_username);
edt_username.setLongClickable(false);
edt_username.setTextIsSelectable(false);
edt_username.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
return false;
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
}
});
}
}
drawable- zeropx.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="0dp"
android:height="0dp"/>
</shape>
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="NoMenuEditText">
<attr name="isCopyPasteDisabled" format="boolean" />
</declare-styleable>
</resources>
At Last, I finally Removed the paste option from the Context Menu of EditText
Thank you StackOverflow posts and http://androidinformative.com/disabling-context-menu/
editText.apply {
setOnTouchListener { v, event ->
if (event.action == KeyEvent.ACTION_DOWN) {
requestFocus()
setSelection(text.toString().length)
showKeyboard()
return#setOnTouchListener true
}
}
}
fun View.showKeyboard() {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(this, 0)
}
Actually in my case i had to set the callback for both selection and insertion and only then i got the copy/paste pop-up to not appear anymore.
Something like this :
private void disableCopyPaste() {
input.setLongClickable(false);
input.setTextIsSelectable(false);
final ActionMode.Callback disableCopyPasteCallback = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
return false;
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
}
};
input.setCustomSelectionActionModeCallback(disableCopyPasteCallback);
input.setCustomInsertionActionModeCallback(disableCopyPasteCallback);
}
Similar to GnrlKnowledge, you can clear the Clipboard
http://developer.android.com/reference/android/text/ClipboardManager.html
If you want, preserve the text in the Clipboard, and on onDestroy, you can set it again.

GWT pasting event

I want to handle events when user pastes some text in TextBox. Which event is fired in this situation? I tried ValueChange and Change handlers, but they didn't work.
This might help you. Describes a workaround to hook to the onpaste event.
In short:
subclass TextBox
sink the onpaste event in the constructor
sinkEvents(Event.ONPASTE);
override onBrowserEvent(Event event)
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
switch (event.getTypeInt()) {
case Event.ONPASTE: {
// do something here
break;
}
}
}
GWT does not yet have support for cut, copy & paste: http://code.google.com/p/google-web-toolkit/issues/detail?id=4030
Edited:
Another option is to use JSNI. For example add this to your GWT class:
public native void addCutHandler(Element element)
/*-{
var temp = this; // hack to hold on to 'this' reference
element.oncut = function(e) {
temp.#org.package.YourClass::handleCut()();
}
}-*/;
public void handleCut() {
Window.alert("Cut!");
}
**(Write In the Constructor)**
sinkEvents( Event.ONPASTE );
**(After that write below code)**
public void onBrowserEvent( Event event )
{
super.onBrowserEvent( event );
switch ( event.getTypeInt() )
{
case Event.ONPASTE :
{
event.stopPropagation();
event.preventDefault();
break;
}
}
}