Flex/Air file dragging: how to restrict filetypes? - drag-and-drop

I'm using a <S:nativeDragDrop> and getting files dragged over a component like so:
var arr:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
I'm not sure how to restrict what type of files can be dragged. Is there a native control for this? The help documents mention the possibility of defining completely different ClipboardFormats, but I have no idea how to do that; I could run regex on the filenames as well, but that seems overcomplicated.
Wondering if there's a way like with FileReference.browse to specify specific file extensions

As far as I know, there is not a built-in way to filter dropped files. However, in your NATIVE_DRAG_ENTER handler, you could loop through the list of files and choose not accept the drag based on their file types. Or, you could merely ignore the unsupported types when you are processing the NATIVE_DRAG_DROP.
var validTypes:Object = {png : true, jpg : true, gif : true};
function nativeDragEnter(event:NativeDragEvent):void {
var files:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array
for each(var file:File in files) {
if(!validTypes[file.extension.toLowerCase()]) // Don't accept drag if any of the dropped files aren't supported.
return;
}
DragManager.acceptDrag(InteractiveObject(event.target));
}
function nativeDragDrop(event:NativeDragEvent):void {
var files:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array
for each(var file:File in files) {
if(validTypes[file.extension]) //accept only certain files
processFile(file);
}
}
As a side note, I assumed you are working on an AIR app here, but if you aren't, you'll have to use the FileReference class instead of File.

Related

store data persistent for learn app with unity

I'm currently working on a language learn app with unity. I want to implement that when you guessed a work (e.g. a number) incorrect, you need to guess the word again in the next iteration. I thought of a way that you store for each word in every play mode a value between +10 to -10 and when an item has a big negative number the word occurrence more often than if it has a big positiv number.
My Problem is that I don't know how to store the data properly. PlayerPrefs are too inconvenient for this problem, and I don't know how to modify a JSON file properly.
Currently, I store the data for the items in a class.
Maybe you could have a structure like:
Numbers
write
zero: -5
one: +3
match
zero: +5
one: +4
Alphabet
write:
A: -10
match:
A: +5
Does anyone have an idea how to solve this problem?
One of the best JSON serialization libraries is Newtonsoft.Json.
You can use your class and serialize an object to JSON object, and then save it as a string to file.
public static string Serialize(object obj)
{
var settings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
};
return JsonConvert.SerializeObject(obj, settings);
}
After that you can save it to file in the Application.persistentDataPath directory.
var text = Serialize(data);
var tmpFilePath = Path.Combine(Application.persistentDataPath, "filename");
Directory.CreateDirectory(Path.GetDirectoryName(tmpFilePath));
if (File.Exists(tmpFilePath))
{
File.Delete(tmpFilePath);
}
File.WriteAllText(tmpFilePath, text);
After that you can read the file at any time using File.ReadAllText and deserialize it to an object.
public static T Deserialize<T>(string text)
{
var settings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
};
try
{
var result = JsonConvert.DeserializeObject<T>(text, settings);
return result ?? default;
}
catch (Exception e)
{
Debug.Log(e);
}
return default;
}
T result = default;
try
{
if (File.Exists(path))
{
var text = File.ReadAllText(path);
result = Deserialize<T>(text);
}
}
catch (Exception e)
{
Debug.LogException(e);
}
return result;
Unfortunately, there is no easy way to store data persistently between play sessions in Unity. PlayerPrefs and creating your own JSON file are the simplest ways of doing this.
The good news is that JSON files are quite easy to make and modify, thanks to the builtin JSONUtility Unity provides.
If you make a separate class or struct to hold your scores, give that clas a [Serializable] tag and keep a reference to that in your current setup (which is probably a MonoBehaviour).
You can use the File class (specifically File.CreateText() and File.OpenText()) to write to/read from a file. If you do this every time a value changes, you should end up with persistent saved data across multiple play sessions.

xPages REST Service Results into Combobox or Typeahead Text Field

I've read all the documentation I can find and watched all the videos I can find and don't understand how to do this. I have set up an xPages REST Service and it works well. Now I want to place the results of the service into either a combobox or typeahead text field. Ideally I would like to know how to do it for both types of fields.
I have an application which has a view containing a list of countries, another view containing a list of states, and another containing a list of cities. I would like the first field to only display the countries field from the list of data it returns in the XPages REST Service. Then, depending upon which country was selected, I would like the states for that country to be listed in another field for selection, etc.
I can see code for calling the REST Service results from a button, or from a dojo grid, but I cannot find how to call it to populate either of the types of fields identified above.
Where would I call the Service for the field? I had thought it would go in the Data area, but perhaps I've just not found the right syntax to use.
November 6, 2017:
I have been following your suggestion, but am still lost as can be. Here's what I currently have in my code:
x$( "#{id:ApplCountry}" ).select2({
placeholder: "select a country",
minimumInputLength: 2,
allowClear : true,
multiple: false,
ajax: {
dataType: 'text/plain',
url: "./Application.xsp/gridData",
quietMillis: 250,
data: function (params) {
return {
search:'[name=]*'+params.term+'*',
page: params.page
};
},
processResults: function (data, page) {
var data = $.map(data, function (obj) {
obj.id = obj.id || obj["#entityid"];
obj.text = obj.text || obj.name;
return obj;
});
},
return {results: data};
}
}
});
I'm using the dataType of 'text/plain' because that was what I understood I should use when gathering data from a domino application. I have tried changing this to json but it makes no difference.
I'm using processResults because I understand this is what should be used in version 4 of select2.
I don't understand the whole use of the hidden field, so I've stayed away from that.
No matter what I do, although my REST service works if I put it directly in the url, I cannot get any data to display in the field. All I want to display in the field is the country code of the document, which is in the field named "name" (not my choice, it's how it came before I imported the data from MySQL.
I have read documentation and watched videos, but still don't really understand how everything fits together. That was my problem with the REST service. If you use it in Dojo, you just put the name of the service in a field on the Dojo element and it's done, so I don't understand why all the additional coding for another type of domino element. Shouldn't it work the same way?
I should point out that at some points it does display the default message, so it does find the field. Just doesn't display the country selections.
I think the issue may be that you are not returning SelectItems to your select2, and that is what it is expecting. When I do something like you are trying, I actually use a bean to generate the selection choices. You may want to try that or I'm putting in the working part of my bean below.
The Utils.getItemValueAsString is a method I use to return either the string value of a field, or if it is not on the document/empty/null an empty string. I took out an if that doesn't relate to this, so there my be a mismatch, but I hope not.
You might be able to jump directly to populating the arrayList, but as I recall I needed to leverage the LinkedHashMap for something.
You should be able to do the same using SSJS, but since that renders to Java before executing, I find this more efficient.
For label/value pairs:
LinkedHashMap lhmap = new LinkedHashMap();
Document doc = null;
Document tmpDoc = null;
allObjects.addElement(doc);
if (dc.getCount() > 0) {
doc = dc.getFirstDocument();
while (doc != null) {
lhmap.put(Utils.getItemValueAsString(doc, LabelField, true), Utils.getItemValueAsString(doc, ValueField, true));
}
tmpDoc = dc.getNextDocument(doc);
doc.recycle();
doc = tmpDoc;
}
}
List<SelectItem> options = new ArrayList<SelectItem>();
Set set = lhmap.entrySet();
Iterator hsItr = set.iterator();
while (hsItr.hasNext()) {
Map.Entry me = (Map.Entry) hsItr.next();
// System.out.println("after: " + hStr);
SelectItem option = new SelectItem();
option.setLabel(me.getKey() + "");
option.setValue(me.getValue() + "");
options.add(option);
}
System.out.println("About to return from generating");
return options;
}
I ended up using straight up SSJS. Worked like a charm - very simple.

How to determine if something was copied or cut to the clipboard

in my #execute method I am able to get the selection out of the clipboard / LocalSelectionTransfer. But I have no idea how to react on that based on how the user has put the content to the clipboard.
I have to decide whether I duplicate or not the content.
This is what I have:
#Execute
public void execute(#Named(IServiceConstants.ACTIVE_SHELL) Shell shell, #Named(IServiceConstants.ACTIVE_PART) MPart activePart) {
Clipboard clipboard = new Clipboard(shell.getDisplay());
TransferData[] transferDatas = clipboard.getAvailableTypes();
boolean weCanUseIt= false;
for(int i=0; i<transferDatas.length; i++) {
if(LocalSelectionTransfer.getTransfer().isSupportedType(transferDatas[i])) {
weCanUseIt = true;
break;
}
}
if (weCanUseIt) {
#SuppressWarnings("unchecked")
List<Object> objects = ((StructuredSelection)LocalSelectionTransfer.getTransfer().getSelection()).toList();
for(Object o: objects) {
System.out.println(o.getClass());
}
}
}
any Ideas???
You only get something in the clipboard using LocalSelectionTransfer if you code a part in your RCP to use this transfer type for a Copy operation. It provides a way to transfer the selection directly.
This transfer type will not be used if something is copied to the clipboard any other way (in this case it might be something like TextTransfer or FileTransfer).
So you will only be using LocalSelectionTransfer to deal with a selection from another part in which case you presumably know how to deal with the objects.
If you are trying to do Copy and Cut then you should do the Cut in the source viewer - but this will remove the selection so you can't use LocalSelectionTransfer for that. Use a transfer such as FileTransfer or TextTransfer which doesn't rely on the current selection.

How to edit pasted content using the Open XML SDK

I have a custom template in which I'd like to control (as best I can) the types of content that can exist in a document. To that end, I disable controls, and I also intercept pastes to remove some of those content types, e.g. charts. I am aware that this content can also be drag-and-dropped, so I also check for it later, but I'd prefer to stop or warn the user as soon as possible.
I have tried a few strategies:
RTF manipulation
Open XML manipulation
RTF manipulation is so far working fairly well, but I'd really prefer to use Open XML as I expect it to be more useful in the future. I just can't get it working.
Open XML Manipulation
The wonderfully-undocumented (as far as I can tell) "Embed Source" appears to contain a compound document object, which I can use to modify the copied content using the Open XML SDK. But I have been unable to put the modified content back into an object that lets it be pasted correctly.
The modification part seems to work fine. I can see, if I save the modified content to a temporary .docx file, that the changes are being made correctly. It's the return to the clipboard that seems to be giving me trouble.
I have tried assigning just the Embed Source object back to the clipboard (so that the other types such as RTF get wiped out), and in this case nothing at all gets pasted. I've also tried re-assigning the Embed Source object back to the clipboard's data object, so that the remaining data types are still there (but with mismatched content, probably), which results in an empty embedded document getting pasted.
Here's a sample of what I'm doing with Open XML:
using OpenMcdf;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
...
object dataObj = Forms.Clipboard.GetDataObject();
object embedSrcObj = dateObj.GetData("Embed Source");
if (embedSrcObj is Stream)
{
// read it with OpenMCDF
Stream stream = embedSrcObj as Stream;
CompoundFile cf = new CompoundFile(stream);
CFStream cfs = cf.RootStorage.GetStream("package");
byte[] bytes = cfs.GetData();
string savedDoc = Path.GetTempFileName() + ".docx";
File.WriteAllBytes(savedDoc, bytes);
// And then use the OpenXML SDK to read/edit the document:
using (WordprocessingDocument openDoc = WordprocessingDocument.Open(savedDoc, true))
{
OpenXmlElement body = openDoc.MainDocumentPart.RootElement.ChildElements[0];
foreach (OpenXmlElement ele in body.ChildElements)
{
if (ele is Paragraph)
{
Paragraph para = (Paragraph)ele;
if (para.ParagraphProperties != null && para.ParagraphProperties.ParagraphStyleId != null)
{
string styleName = para.ParagraphProperties.ParagraphStyleId.Val;
Run run = para.LastChild as Run; // I know I'm assuming things here but it's sufficient for a test case
run.RunProperties = new RunProperties();
run.RunProperties.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Text("test"));
}
}
// etc.
}
openDoc.MainDocumentPart.Document.Save(); // I think this is redundant in later versions than what I'm using
}
// repackage the document
bytes = File.ReadAllBytes(savedDoc);
cf.RootStorage.Delete("Package");
cfs = cf.RootStorage.AddStream("Package");
cfs.Append(bytes);
MemoryStream ms = new MemoryStream();
cf.Save(ms);
ms.Position = 0;
dataObj.SetData("Embed Source", ms);
// or,
// Clipboard.SetData("Embed Source", ms);
}
Question
What am I doing wrong? Is this just a bad/unworkable approach?

Protovis - dealing with a text source

lets say I have a text file with lines as such:
[4/20/11 17:07:12:875 CEST] 00000059 FfdcProvider W com.test.ws.ffdc.impl.FfdcProvider logIncident FFDC1003I: FFDC Incident emitted on D:/Prgs/testing/WebSphere/AppServer/profiles/ProcCtr01/logs/ffdc/server1_3d203d20_11.04.20_17.07.12.8755227341908890183253.txt com.test.testserver.management.cmdframework.CmdNotificationListener 134
[4/20/11 17:07:27:609 CEST] 0000005d wle E CWLLG2229E: An exception occurred in an EJB call. Error: Snapshot with ID Snapshot.8fdaaf3f-ce3f-426e-9347-3ac7e8a3863e not found.
com.lombardisoftware.core.TeamWorksException: Snapshot with ID Snapshot.8fdaaf3f-ce3f-426e-9347-3ac7e8a3863e not found.
at com.lombardisoftware.server.ejb.persistence.CommonDAO.assertNotNull(CommonDAO.java:70)
Is there anyway to easily import a data source such as this into protovis, if not what would the easiest way to parse this into a JSON format. For example for the first entry might be parsed like so:
[
{
"Date": "4/20/11 17:07:12:875 CEST",
"Status": "00000059",
"Msg": "FfdcProvider W com.test.ws.ffdc.impl.FfdcProvider logIncident FFDC1003I",
},
]
Thanks, David
Protovis itself doesn't offer any utilities for parsing text files, so your options are:
Use Javascript to parse the text into an object, most likely using regex.
Pre-process the text using the text-parsing language or utility of your choice, exporting a JSON file.
Which you choose depends on several factors:
Is the data somewhat static, or are you going to be running this on a new or dynamic file each time you look at it? With static data, it might be easiest to pre-process; with dynamic data, this may add an annoying extra step.
How much data do you have? Parsing a 20K text file in Javascript is totally fine; parsing a 2MB file will be really slow, and will cause the browser to hang while it's working (unless you use Workers).
If there's a lot of processing involved, would you rather put that load on the server (by using a server-side script for pre-processing) or on the client (by doing it in the browser)?
If you wanted to do this in Javascript, based on the sample you provided, you might do something like this:
// Assumes var text = 'your text';
// use the utility of your choice to load your text file into the
// variable (e.g. jQuery.get()), or just paste it in.
var lines = text.split(/[\r\n\f]+/),
// regex to match your log entry beginning
patt = /^\[(\d\d?\/\d\d?\/\d\d? \d\d:\d\d:\d\d:\d{3} [A-Z]+)\] (\d{8})/,
items = [],
currentItem;
// loop through the lines in the file
lines.forEach(function(line) {
// look for the beginning of a log entry
var initialData = line.match(patt);
if (initialData) {
// start a new item, using the captured matches
currentItem = {
Date: initialData[1],
Status: initialData[2],
Msg: line.substr(initialData[0].length + 1)
}
items.push(currentItem);
} else {
// this is a continuation of the last item
currentItem.Msg += "\n" + line;
}
});
// items now contains an array of objects with your data