Remove multiple rows in a single pass in JTable AbstractDataModel - swing

i've got an issue with Jtable and my dataModel.
My table model extends AbstracttableModel, the datas are stored in a Vector.
I'have a function witch is suppose to remove one or more row.
These rows are not necessarily contiguous because my jtable set a selectionMode as this:
jTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
The function to remove row (one by one):
public void removeMessageRow(Integer p_idMessage) {
Enumeration<MlMessage> alldatas = vData.elements();
while (alldatas.hasMoreElements()) {
MlMessage m = alldatas.nextElement();
if (m.getIdMessage() == p_idMessage) {
int idx = vData.indexOf(m);
boolean result = vData.remove(m);
// fireTableDataChanged();
// fireTableRowsDeleted(idx, idx);
fireTableStructureChanged();
return;
}
}
When i launch the function, i execute the loop without problem, in step-by-step mode, i can see the vData object updated and if i execute this only one time there is no probleme with the GUI. The problem appear when i select more than one row.
For example, i selected row number 0 and number 1 in my table and i lauch the function removeMessageRow, at the first execution, the vDataObject is correctly updated (all the datas are shiffted and the last elements of this vector is set to null by the call to vData.remove(m).
So in my case, i expect that at the second execution, the object to find should be at position 0 but it's at position 1 as the vData Object as never been updated.
Does anybody have an idea about that?
I've tried many on fire... stuff but no one semms to execute immediatly.
Thanks for any help by advance and sorry for my Shakespeare's language.

Add a method in your model taking a collection of indices to remove (Set<Integer>, or int[]), sort this collection, iterate backwards in this collection, and remove the elements in the list of objects of your model:
public void removeRows(int[] indices) {
Arrays.sort(indices);
for (int i = indices.length - 1; i >= 0; i--) {
this.data.remove(indices[i]);
fireTableRowsDeleted(indices[i], indices[i]);
}
}

int[] selectedRow = tblUsuarios.getSelectedRows();
int del=1;
for(int j=0; j<selectedRow.length; j++){
modTabla.removeRow(selectedRow[j]);
if(j<selectedRow.length-1){
selectedRow[j+1] = selectedRow[j+1]-del;
del = del+1;
}
}
//modTabla = defaultTableModel
//tblUsuarios = jtable

Related

implement the next function of interable to iterate over a 2D array in kotlin

I have a custom class that is array<array<K>>. I want to iterate over it with forEach, you know, the way we do with arrays in kotlin. I implement the iterable<k> and the hasNext function is easy. Problem is, the next function is hard because now I have columns and the columns are of different sizes.
I would appreciate it if you could tell me how to write next(). Some hints in the right direction is fine.
Here is the answer to my own question. In fact, I am doing this as a self-set exercise to a tutorial about coding a hashmap.
override fun iterator(): Iterator<K> {
return object : Iterator<K> {
var stopLoopNumber = 0
var rowEntry = 0
var columnEntry = 0
override fun hasNext(): Boolean {
return stopLoopNumber < getAllEntries()
}
override fun next(): K {
//check if a row has more than one entry. if so, increment the column to output all entries in the column.
//at the same time increment the stopLoopNumber each time an entry is output.
return if (columnEntry < entries[rowEntry].size) {
stopLoopNumber++
entries[rowEntry][columnEntry++].key
} else {
// the column is exhausted, so reset it to 0, ready for the next row.
columnEntry = 0
stopLoopNumber++
//move to the next row and after outputting the entry, increment the column. This is vital because we must
//increment the column after an entry is output.
entries[++rowEntry][columnEntry++].key
}
}
}
}

Combining two items (recipe-like)

I'd like a user to be able to combine two items and if compatible will yield a new item. In this example, the item IDs will be saved as Strings.
I was wondering what the most efficient way to do this would be, while making sure that swapped order will always yield the same result, so the user could input the order:
item X + item Y = item Z
item Y + item X = item Z
I've tried using Dictionaries and Objects, but I just haven't been able to get anything to work. I've also tried some various libraries that include HashMap/HashSet but nothing is working. here's some pseduo-code:
itemRecipe1:HashSet = new HashSet();
itemRecipe1.add("2");//Add item with ID of 2
itemRecipe1.add("3");//Add item with ID of 3
inputRecipe:HashSet = new HashSet();
inputRecipe.add("3");//Add item with ID of 3 (swapped)
inputRecipe.add("2");//Add item with ID of 2 (swapped)
recipeList:HashMap = new HashMap();
receipeList.put(itemRecipe1, "11");//Recipe has been added, the result of the recipe should be item 11
//This should output as TRUE since the composition of itemRecipe1 and inputRecipe are the same, despite a different input order.
trace(receipeList.containsKey(inputRecipe));
If anyone has a solution for this issue, please elt me know as I am willing to implement any design I can get working. I just don't see how a Dictionary could work as the key order matters.
So you're trying to associate two or more objects with each other. The first thing you need is some primitive data you can use to represent each item uniquely, typically an ID. This should give you something like the following to begin with:
class Item {
public var _id:int;
public function Item(id:int) {
_id = id;
}
public function get id():int { return _id; }
}
Now you need some piece of data that establishes a relationship between multiple Items using this ID. That could be as simple as the following, with a little extra functionality thrown in to see if an input list of these IDs matches the relationship:
class ItemRelationship {
private var _items:Vector.<Item>;
public function ItemRelationship(items:Vector.<Item>) {
_items = items;
}
public function matches(ids:Vector.<int>):Boolean {
if (_items.length !== ids.length) {
return false;
}
for each (var item:Item in _items) {
var found:Boolean = false;
for each (var id:int in ids) {
if (item.id === id) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
public function get items():Vector.<Item> { return _items; }
}
This lets us do something like this, assuming we have a bunch of items (item1, item2, ...) with IDs.
var rel:ItemRelationship = new ItemRelationship(new <Item>[item1, item2]);
And then:
trace(rel.matches(new <int>[1,2])); // true
trace(rel.matches(new <int>[2,1])); // true
trace(rel.matches(new <int>[3,4])); // false
Now all we need is something that stores all of these relationships and lets us fetch one based on a list of input IDs:
class RelationshipCollection {
private var _relationships:Vector.<ItemRelationship>;
public function RelationshipCollection(relationships:Vector.<ItemRelationship>) {
_relationships = relationships;
}
public function find(ids:Vector.<int>):ItemRelationship {
for each(var relationship:ItemRelationship in _relationships) {
if (relationship.matches(ids)) return relationship;
}
return null;
}
}
Put a load of relationships in there:
var collection:RelationshipCollection = new RelationshipCollection(new <ItemRelationship>[
new ItemRelationship(new <Item>[item1, item4]),
new ItemRelationship(new <Item>[item2, item3])
]);
And give it a whirl:
trace(collection.find(new <int>[1, 3])); // null (no match)
trace(collection.find(new <int>[1, 4])); // works
trace(collection.find(new <int>[3, 2])); // works
trace(collection.find(new <int>[2, 3])); // works
Of course for the sake of readability you can rename each class to something more appropriate for its application e.g. Item => Potion, ItemRelationship => Recipe, RelationshipCollection => RecipeBook.
so the user could input the order
The first step is to limit the possible input. If you allow any type of input, you have to parse that input and things get complicated very quickly.
Create an input method that only allows the user to put two items together, say for example via drag and drop of the items to only 2 slots.
I just don't see how a Dictionary could work as the key order matters.
The important part is to design the keys well.
As #George Profenza pointed out in the comments, you could change your IDs to a different format. Instead of having 1, 2, 3, ... n you could use 1, 2, 4, ... 2^n. The advantage is that you can combine any two IDs uniquely via bitwise or operator (|). In the following example, two such IDs are combined (binary notation):
00001
| 10000
--------
10001
As you can see, each ID occupies a separate position in binary: the 1st position and the 5th. Combining both via or operator means that now both 1st and 5th position are 1. The order doesn't matter. If you use such IDs in the form of powers of 2 you can combine them regardless of the order to form pairs, which can then be used as keys to a dictionary.
Another solution is to simply sort the pair of IDs.
The combination 3-2 becomes 2-3 and the combination 2-3 stays 2-3. Both 2-3 and 3-2 lead to the same result.
You can then build your data structure accordingly, that is: the outer data structure is for the lower ID number and the nested, inner one is for the bigger ID number. Here's some pseudo code with generic objects:
var map:Object = {};
map["2"] = {"3":"combination 2-3"};
To access that, you'd do something like:
trace(map[Math.min(ID1, ID2)][Math.max(ID1, ID2)])
There's also the brute force way of doing it by storing both possible combinations in the data structure. The code for that could roughly look like that:
var map:Object = {};
map["2"] = {"3":"combination 2-3"};
map["3"] = {"2":"combination 2-3"};
Now both
trace(map[ID1][ID2]);
and
trace(map[ID2][ID1]);
Should yield the same result.

Warning messages with EZAPI EzDerivedColumn and input columns

When adding a derived column to a data flow with ezAPI, I get the following warnings
"Add stuff here.Inputs[Derived Column Input].Columns[ad_zip]" on "Add
stuff here" has usage type READONLY, but is not referenced by an
expression. Remove the column from the list of available input
columns, or reference it in an expression.
I've tried to delete the input columns, but either the method is not working or I'm doing it wrong:
foreach (Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSInputColumn100 col in derFull.Meta.InputCollection[0].InputColumnCollection)
{
Console.WriteLine(col.Name);
derFull.DeleteInputColumn(col.Name);
}
I have the following piece of code that fixes the problem.
I got it from a guy called Daniel Otykier. So he is propably the one that should be credited for it... Unlesss he got it from someone else :-)
static public void RemoveUnusedInputColumns(this EzDerivedColumn component)
{
var usedLineageIds = new HashSet<int>();
// Parse all expressions used in new output columns, to determine which input lineage ID's are being used:
foreach (IDTSOutputColumn100 column in component.GetOutputColumns())
{
AddLineageIdsFromExpression(column.CustomPropertyCollection, usedLineageIds);
}
// Parse all expressions in replaced input columns, to determine which input lineage ID's are being used:
foreach (IDTSInputColumn100 column in component.GetInputColumns())
{
AddLineageIdsFromExpression(column.CustomPropertyCollection, usedLineageIds);
}
var inputColumns = component.GetInputColumns();
// Remove all input columns not used in any expressions:
for (var i = inputColumns.Count - 1; i >= 0; i--)
{
if (!usedLineageIds.Contains(inputColumns[i].LineageID))
{
inputColumns.RemoveObjectByIndex(i);
}
}
}
static private void AddLineageIdsFromExpression(IDTSCustomPropertyCollection100 columnProperties, ICollection<int> lineageIds)
{
int lineageId = 1;
var expressionProperty = columnProperties.Cast<IDTSCustomProperty100>().FirstOrDefault(p => p.Name == "Expression");
if (expressionProperty != null)
{
// Input columns used in expressions are always referenced as "#xxx" where xxx is the integer lineage ID.
var expression = expressionProperty.Value.ToString();
var expressionTokens = expression.Split(new[] { ' ', ',', '(', ')' });
foreach (var c in expressionTokens.Where(t => t.Length > 1 && t.StartsWith("#") && int.TryParse(t.Substring(1), out lineageId)))
{
if (!lineageIds.Contains(lineageId)) lineageIds.Add(lineageId);
}
}
}
Simple but not 100% Guaranteed Method
Call ReinitializeMetaData on the base component that EzApi is extending:
dc.Comp.ReinitializeMetaData();
This doesn't always respect some of the customizations and logic checks that EzAPI has, so test it carefully. For most vanilla components, though, this should work fine.
100% Guaranteed Method But Requires A Strategy For Identifying Columns To Ignore
You can set the UsageType property of those VirtualInputColumns to the enumerated value DTSUsageType.UT_IGNORED using EzApi's SetUsageType wrapper method.
But! You have to do this after you're done modifying any of the other metadata of your component (attaching other components, adding new input or output columns, etc.) since each of these triggers the ReinitializeMetaData method on the component, which automatically sets (or resets) all UT_IGNORED VirtualInputColumn's UsageType to UT_READONLY.
So some sample code:
// define EzSourceComponent with SourceColumnToIgnore output column, SomeConnection for destination
EzDerivedColumn dc = new EzDerivedColumn(this);
dc.AttachTo(EzSourceComponent);
dc.Name = "Errors, Go Away";
dc.InsertOutputColumn("NewDerivedColumn");
dc.Expression["NewDerivedColumn"] = "I was inserted!";
// Right here, UsageType is UT_READONLY
Console.WriteLine(dc.VirtualInputCol("SourceColumnToIgnore").UsageType.ToString());
EzOleDbDestination d = new EzOleDbDestination(f);
d.Name = "Destination";
d.Connection = SomeConnection;
d.Table = "dbo.DestinationTable";
d.AccessMode = AccessMode.AM_OPENROWSET_FASTLOAD;
d.AttachTo(dc);
// Now we can set usage type on columns to remove them from the available inputs.
// Note the false boolean at the end.
// That's required to not trigger ReinitializeMetadata for usage type changes.
dc.SetUsageType(0, "SourceColumnToIgnore", DTSUsageType.UT_IGNORED, false);
// Now UsageType is UT_IGNORED and if you saved the package and viewed it,
// you'll see this column has been removed from the available input columns
// ... and the warning for it has gone away!
Console.WriteLine(dc.VirtualInputCol("SourceColumnToIgnore").UsageType.ToString());
I was having exactly your problem and found a way to solve it. The problem is that the EzDerivedColumn has not the PassThrough defined in it's class.
You just need to add this to the class:
private PassThroughIndexer m_passThrough;
public PassThroughIndexer PassThrough
{
get
{
if (m_passThrough == null)
m_passThrough = new PassThroughIndexer(this);
return m_passThrough;
}
}
And alter the ReinitializeMetadataNoCast() to this:
public override void ReinitializeMetaDataNoCast()
{
try
{
if (Meta.InputCollection[0].InputColumnCollection.Count == 0)
{
base.ReinitializeMetaDataNoCast();
LinkAllInputsToOutputs();
return;
}
Dictionary<string, bool> cols = new Dictionary<string, bool>();
foreach (IDTSInputColumn100 c in Meta.InputCollection[0].InputColumnCollection)
cols.Add(c.Name, PassThrough[c.Name]);
base.ReinitializeMetaDataNoCast();
foreach (IDTSInputColumn100 c in Meta.InputCollection[0].InputColumnCollection)
{
if (cols.ContainsKey(c.Name))
SetUsageType(0, c.Name, cols[c.Name] ? DTSUsageType.UT_READONLY : DTSUsageType.UT_IGNORED, false);
else
SetUsageType(0, c.Name, DTSUsageType.UT_IGNORED, false);
}
}
catch { }
}
That is the strategy used by other components. If you want to see all the code you can check my EzApi2016#GitHub. I'm updating the original code from Microsoft to SQL Server 2016.

Randomly selecting an object property

I guess a step back is in order. My original question is at the bottom of this post for reference.
I am writing a word guessing game and wanted a way to:
1. Given a word length of 2 - 10 characters, randomly generate a valid english word to guess
2.given a 2 - 10 character guess, ensure that it is a valid english word.
I created a vector of 9 objects, one for each word length and dynamically created 172000
property/ value pairs using the words from a word list to name the properties and setting their value to true. The inner loop is:
for (i = 0; i < _WordCount[wordLength] - 2; i)
{
_WordsList[wordLength]["" + _WordsVector[wordLength][i++]] = true;
}
To validate a word , the following lookup returns true if valid:
function Validate(key:String):Boolean
{
return _WordsList[key.length - 2][key]
}
I transferred them from a vector to objects to take advantage of the hash take lookup of the properties. Haven't looked at how much memory this all takes but it's been a useful learning exercise.
I just wasn't sure how best to randomly choose a property from one of the objects. I was thinking of validating whatever method I chose by generating 1000 000 words and analyzing the statistics of the distribution.
So I suppose my question should really first be am I better off using some other approach such as keeping the lists in vectors and doing a search each time ?
Original question
Newbie first question:
I read a thread that said that traversal order in a for.. in is determined by a hash table and appears random.
I'm looking for a good way to randomly select a property in an object. Would the first element in a for .. in traversing the properties, or perhaps the random nth element in the iteration be truly random. I'd like to ensure that there is approximately an equal probability of accessing a given property. The Objects have between approximately 100 and 20000 properties. Other approaches ?
thanks.
Looking at the scenario you described in your edited question, I'd suggest using a Vector.<String> and your map object.
You can store all your keys in the vector and map them in the object, then you can select a random numeric key in the vector and use the result as a key in the map object.
To make it clear, take a look at this simple example:
var keys:Vector.<String> = new Vector.<String>();
var map:Object = { };
function add(key:String, value:*):void
{
keys.push(key);
map[key] = value;
}
function getRandom():*
{
var randomKey = keys[int(Math.random() * keys.length)];
return map[randomKey];
}
And you can use it like this:
add("a", "x");
add("b", "y");
add("c", "z");
var radomValue:* = getRandom();
Using Object instead of String
Instead of storing the strings you can store objects that have the string inside of them,
something like:
public class Word
{
public var value:String;
public var length:int;
public function Word(value:String)
{
this.value = value;
this.length = value.length;
}
}
Use this object as value instead of the string, but you need to change your map object to be a Dictionary:
var map:Dictionary = new Dictionary();
function add(key:Word, value:*):void
{
keys.push(key);
map[key] = value;
}
This way you won't duplicate every word (but will have a little class overhead).

Create a Non-Database-Driven Lookup

Lots of references for creating lookups out there, but all seem to draw their values from a query.
I want to add a lookup to a field that will add items from a list of values that do not come from a table, query, or any other data source.
Such as from a string: "Bananas, Apples, Oranges"
..or a container ["Bananas", "Apples", "Oranges"]
Assume the string/container is a dynamic object. Drawing from an static enum is not a choice.
Is there a way to create lookups on the fly from something other than a data source?
Example code would be a great help, but I'll take hints as well.
There is the color picker.
Also in the Global you will find pickXxxx such as pickList.
There are others, pickUser, pickUserGroup etc.
Take a look on the implementation. I guess they build a temporary table then displays that. Tables are great!
Update:
To go on you own follow the rules.
For the advanced user, see also: Lookup form returning more than one value.
public void lookup()
{
SysTableLookup sysTableLookup;
TmpTableFieldLookup tmpTableFieldLookup;
Enumerator en;
List entitylist = new list(types::String);
entitylist.addend("Banana");
entitylist.addend("Apple");
en = entityList.getEnumerator();
while (en.moveNext())
{
tmpTableFieldLookup.TableName = en.current();
tmpTableFieldLookup.insert();
}
sysTableLookup = SysTableLookup::newParameters(tableNum(tmpTableFieldLookup), this);
sysTableLookup.addLookupfield(fieldNum(TmpTableFieldLookup, TableName));
//BP Deviation documented
sysTableLookup.parmTmpBuffer(tmpTableFieldLookup);
sysTableLookup.performFormLookup();
}
The above code helps in displaying strings as lookup.
I'm also guessing there's no way to perform a lookup without a table. I say that because a lookup is simply a form with one or more datasources that is displayed in a different way.
I've also blogged about this, so you can get some info on how to perform a lookup, even with a temporary table, here:
http://devexpp.blogspot.com.br/2012/02/dynamics-ax-custom-lookup.html
Example from global::PickEnumValue:
static int pickEnumValue(EnumId _enumId, boolean _omitZero = false)
{
Object formRun;
container names;
container values;
int i,value = -1,valueIndex;
str name;
#ResAppl
DictEnum dictEnum = new DictEnum(_enumId);
;
if (!dictEnum)
return -1;
for (i=1;i<=dictEnum.values();i++)
{
value = dictEnum.index2Value(i);
if (!(_omitZero && (value == 0)))
{
names += dictEnum.index2Label(i);
values += value;
}
}
formRun = classfactory.createPicklist();
formRun.init();
formRun.choices(names, #ImageClass);
formRun.caption(dictEnum.label());
formRun.run();
formRun.wait();
name = formRun.choice();
value = formRun.choiceInt();
if (value>=0) // the picklist form returns -1 if a choice has not been made
{
valueIndex = -1;
for (i=1;i<=conLen(names);i++)
{
if (name == conPeek(names,i))
{
valueIndex = i;
break;
}
}
if (valueIndex>=0)
return conPeek(values,valueIndex);
}
return value;
}
It isn't the most graceful solution, but this does work, and it doesn't override or modify any native AX 2012 objects:
Copy the sysLookup form from AX2009 (rename it) and import it into AX 2012.
We'll call mine myLookupFormCopy.
I did a find/replace of "sysLookup" in the XPO file to rename it.
Create this class method:
public static client void lookupList(FormStringControl _formStringControl, List _valueList, str _columnLabel = '')
{
Args args;
FormRun formRun;
;
if (_formStringControl && _valueList && _valueList.typeId() == Types::String)
{
args = new Args(formstr(myLookupFormCopy));
args.parmObject(_valueList);
args.parm(_columnLabel);
formRun = classFactory.formRunClass(args);
_formStringControl.performFormLookup(formRun);
}
}
In the lookup method for your string control, use:
public void lookup()
{
List valueList = new List(Types::String);
;
...build your valueList here...
MyClass::lookupList(this, valueList, "List Title");
super();
}