Using Drag-Sort ListView with SQLite DB - drag-and-drop

I'm trying to create a simple to-do-list app with an SQLite DB and a Drag-Sort ListView.
Right now I am binding data from an SQLite database cursor into a ListView using a SimpleCursorAdapter and adding items with an EditText view as explained in this tutorial.
I have moved everything into one activity and I have swapped the plain ListView with a Drag-Sort ListView. My issue is connecting the DB and Drag-Sort ListView together. The DLSV demos use a predefined array to fill fill the DSLV.
Snippet form DSLV:
DragSortListView lv = (DragSortListView) getListView();
lv.setDropListener(onDrop);
lv.setRemoveListener(onRemove);
array = getResources().getStringArray(R.array.jazz_artist_names);
list = new ArrayList<String>(Arrays.asList(array));
adapter = new ArrayAdapter<String>(this, R.layout.list_item1, R.id.text1, list);
setListAdapter(adapter);
Snippet from my existing code:
mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();
...
mDbHelper.createNote(noteName, "");
fillData();
private void fillData() {
// Get all of the notes from the database and create the item list
Cursor c = mDbHelper.fetchAllNotes();
startManagingCursor(c);
String[] from = new String[] { NotesDbAdapter.KEY_TITLE };
int[] to = new int[] { R.id.text1 };
// Now create an array adapter and set it to display using our row
SimpleCursorAdapter notes =
new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);
}
Thank you and sorry if this doesn't make all that much sense.

Since you cannot reorder the items in a Cursor, you have to create a mapping between Cursor positions and ListView positions. This is done for you by the DragSortCursorAdapter class and subclasses so that the drag and drop reordering is maintained visually. If you need the new orders persisted (like to your database), then you must implement that logic yourself. The method getCursorPositions() will help you with this.

I have made use of Drag sort list view. Its amazing! but instead of using the dragsortcursoradapter i created my own trick. here it is.
What i have done is that whenever i swapped any item, i passed the new swapped list in an array to the database, deleted the table and recreated the new updated table. here is my code
here is the code snippet from my database handler
public void onUpdateToDoTable(ArrayList<Task> taskList) {
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("DROP TABLE IF EXISTS " + TABLE_TASKTODO);
String CREATE_TASK_TODO_TABLE = "CREATE TABLE IF NOT EXISTS "
+ TABLE_TASKTODO + "(" + SEQ_ID + " INTEGER PRIMARY KEY,"
+ TASK_NAME + " TEXT )";
db.execSQL(CREATE_TASK_TODO_TABLE);
for (int i = 0; i < taskList.size(); i++) {
ContentValues values = new ContentValues();
values.put(TASK_NAME, taskList.get(i).getTask());
db.insert(TABLE_TASKTODO, null, values);
}
db.close();
}
then on using drop listener
i called the above method..
private DragSortListView.DropListener onDrop = new DragSortListView.DropListener() {
#Override
public void drop(int from, int to) {
Task item = adapter.getItem(from);
adapter.notifyDataSetChanged();
adapter.remove(item);
adapter.insert(item, to);
db.onUpdateToDoTable(list);
Log.d("LIST", db.getAllToDoTasks().toString());
}
};
db is my object of database handler. whole source code is available at dragdroplistview. amazing example. this was a life saver for me. Ciao!

There is a github project available at https://github.com/jmmcreynolds/dslv-db-demo
This demo includes a working example of how to setup a DragSortListView that will save the changes that you make to the list (position, add/delete) to a database.
I have used it just now. Its perfect demo project available for using DSLV with SQLiteDB.
Thanks to github user jmmcreynolds.

Related

Need clarification about how to apply a custom update to data adapter source

I have created a record-view form that contains a few bound elements via a BindingSource and a BindingNavigator. The viewing of the data fields is operating correctly. Note that the variables da and ds are global in this form.
private void frmItem_Load(object sender, EventArgs e) {
string scon = System.Configuration.ConfigurationManager.ConnectionStrings["myitems"].ToString();
da = new SqlDataAdapter("Select * From myitems where id > 0 ", scon);
ds = new DataSet();
da.Fill(ds);
bindingSource1.DataSource = ds.Tables[0];
bindingNavigator1.BindingSource = this.bindingSource1;
this.txtId.DataBindings.Add(new Binding("Text", bindingSource1, "id", true));
this.txtItem.DataBindings.Add(new Binding("Text", bindingSource1, "item", true));
this.txtUpdatedwhen.DataBindings.Add(new Binding("Text", bindingSource1, "updatedwhen", true));
}
I am showing this record-view form from a data grid view of items by using a row header mouse dbl-click event. The requested row from the dgv is correctly being selected and its row data is correctly being shown in the record-view form.
private void dgvItems_RowHeaderMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e) {
frmItem gfrmItem = new frmItem();
string sID = this.dgvItems.CurrentRow.Cells[0].Value.ToString();
gfrmItem.FilterByID(sID);
gfrmItem.Show();
}
I've added a save button to the navigator so that I can make individual record save. What I'm attempting to do is programatically apply a date/time stamp update before the record is saved from the button click.
private void btnSave_Click(object sender, EventArgs e)
{
this.txtUpdatedwhen.Text = DateTime.Now.ToString();
da.Update(ds);
}
Although the date/time value is changed per the code and shows in the form, the update is not applying the date/time change.
I thought that the textbox value was being bound to the underlying dataset and would accept changes as if I had entered it manually ... but this is not occurring. I had read some other posts that using the data adapter update is the right way to go about this as apposed to doing something like performing a direct sql update.
I'm stumped with how to resolve this. Any pointers would be greatly appreciated.
After letting this sit a while and coming back to it today, I found a resolution.
There was a common misunderstanding at work that I saw in other posts.
That was that the dataadapter does not automatically populate its commands, even if you pass an active connection into the creation step.
So my resolution was to create a global SqlCommandBuilder variable along with the other ones I was using
SqlDataAdapter da;
SqlConnection sc;
SqlCommandBuilder sb;
DataSet ds;
then create the builder object at form load and initialize the update command into a string variable ... which isn't used there after, but the dataadapter commands are now populated.
string scon = System.Configuration.ConfigurationManager.ConnectionStrings["networkadmin"].ToString();
sc = new SqlConnection(scon);
sc.Open();
string sSelect = "Select * From datatable where id > 0 Order By fld1;";
}
this.da = new SqlDataAdapter(sSelect, sc);
sb = new SqlCommandBuilder(da);
// This initiates the commands, though the target var is not used again.
string uCmd = sb.GetUpdateCommand().ToString();
this.ds = new DataSet();
this.da.Fill(this.ds);
Then the update step does work as expected:
this.txtUpdatedwhen.Text = DateTime.Now.ToString();
DataRowView current = (DataRowView)bindingSource1.Current;
current["updatedwhen"] = this.txtUpdatedwhen.Text;
bindingSource1.EndEdit();
this.da.Update(ds);
I hope this helps someone.

cursor count is 1 whereas the table has 3 rows

I m trying to populate sql table and then retrieve data from it. Following is my code.
public void addQuestion(Question quest)
{
int id = 1;
ContentValues values = new ContentValues();
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("DROP TABLE IF EXISTS " + TABLE_QUEST1);
onCreate(db);
values.put(KEY_QUES, quest.getQuestion());
values.put(KEY_ANSWER, quest.getAnswer());
values.put(KEY_OPTA, quest.getOptA());
values.put(KEY_OPTB, quest.getOptB());
values.put(KEY_OPTC, quest.getOptC());
db.insert(TABLE_QUEST1, null, values);
System.out.println("Added in database: " + quest.getQuestion());
}
public ArrayList<Question> getAllQuestions() {
System.out.println("getting rows 1");
ArrayList<Question> quesList = new ArrayList<Question>();
System.out.println("getting rows 2");
Cursor cursor = null;
SQLiteDatabase db = getReadableDatabase();
System.out.println("getting rows ");
cursor = db.rawQuery("SELECT * FROM " + TABLE_QUEST1, null);
if (!cursor.moveToFirst()) {
System.out.println("No data in the database ");
} else {
System.out.println("theres data in the database ");
quesList = new ArrayList<Question>();
do {
System.out.print("total rows " + cursor.getCount());
Question quest = new Question();
quest.setID(cursor.getInt(0));
quest.setQuestion(cursor.getString(1));
quest.setAnswer(cursor.getString(2));
quest.setOptA(cursor.getString(3));
quest.setOptB(cursor.getString(4));
quest.setOptC(cursor.getString(5));
quesList.add(quest);
} while (cursor.moveToNext());
cursor.close();
}
}
I have 4 rows of data in my table and I can see that with the print statement "added in database"
but when i actually read it the cursor just reads row 1 and moves out of the while loop. what could potentially be wrong.
tia
Your code was absolutely fine except placing drop command in the loop. As mentioned in the earlier comments, please make sure to avoid calling drop query each time and you'll find the result.
As Santosh has pointed out DROPPING the table (as per db.execSQL("DROP TABLE IF EXISTS " + TABLE_QUEST1);) and then re-creating it (as per onCreate(db);) will delete the table and then re-create the table removing any rows/data that had previously been added to the table.
As such it's simply a matter of removing those two lines of code, Also there appears to be no need for the line int id = 1;, so perhaps remove this, as per :-
public void addQuestion(Question quest)
{
ContentValues values = new ContentValues();
SQLiteDatabase db = this.getWritableDatabase();
values.put(KEY_QUES, quest.getQuestion());
values.put(KEY_ANSWER, quest.getAnswer());
values.put(KEY_OPTA, quest.getOptA());
values.put(KEY_OPTB, quest.getOptB());
values.put(KEY_OPTC, quest.getOptC());
db.insert(TABLE_QUEST1, null, values);
System.out.println("Added in database: " + quest.getQuestion());
}
P.S. you may consider not using hard coded column offsets but instead obtain offsets according to column names by utilising the getColumnIndex(column_name) Cursor method. e.g. :-
Question quest = new Question();
quest.setID(cursor.getInt(cursor.getColumnIndex("name_of_your_id_columm")));
quest.setQuestion(cursor.getString(cursor.getColumnIndex(KEY_QUES)));
quest.setAnswer(cursor.getString(cursor.getColumnIndex(KEY_ANSWER)));
quest.setOptA(cursor.getString(cursor.getColumnIndex(KEY_OPTA)));
quest.setOptB(cursor.getString(cursor.getColumnIndex(KEY_OPTB)));
quest.setOptC(cursor.getString(cursor.getColumnIndex(KEY_OPTC)));
quesList.add(quest);
Noting that instead of "name_of_your_id_columm", you may have something like KEY_ID defined, if so use that, thus you have a single definition so it reduces the chance of inadvertently mispelling column names or miscalculating the offsets.

How to add rows to TableView without having any data model

I'm fairly new to javafx, so please bear with me if my question is unclear. I've a TableView which need to be populated using an ObservableList.
The code below populates my "data" with the arraylists generated out of the Map, which in turn is used to add rows to my table.
TableView<ArrayList> table = new TableView<>();
ObservableList<ArrayList> data = FXCollections.observableArrayList();
for(int i=0;i<listSelectedVerticesIds.size();i++){
ArrayList<String> tempString = new ArrayList<>();
for(Map.Entry<String,String> temp2 : mapVertex.get(listSelectedVerticesIds.get(i)).entrySet()){
tempString.add(temp2.getValue());
}
data.add(tempString);
}
table.setItems(data);
However, I do not see the table populated with the list in "data". I'm guessing this is because there is no data binding (using setCellValueFactory). However, as you can see I dont have a data model class. All of my data comes from the Map as strings which I would like to populate in my tableview.
Please suggest.
Here is a simple way to do it that works great. You don't need a data structure to populate a table. You only see that because that's what most examples show. It is an extremely common use case to populate a table from a database or a file. I don't understand why this is so hard to find examples for. Well, hope this helps.
private TableView<ObservableList<StringProperty>> table = new TableView<>();
private ArrayList<String> myList = new ArrayList<>();
private void updateTableRow() {
for (int row = 0; row < numberOfRows; row++) {
ObservableList<StringProperty> data = FXCollections.observableArrayList();
for (int column = 0; column < numberOfColumns; column++) {
data.add(column, new SimpleStringProperty(myList.get(row + (column * numberOfRows))));
}
table.getItems().add(data);
}
}

Updating column in tableviwer

I have retrieved data from database and i am able to show it in Table of the Table Viewer but my task is on click of a row the data should be appear in another form from where i can edit it and on click of update the view should be updated with the new values.I am using viewer.addSelectionChangedListener to retrieve the selected row but i am not getting how to update the table .Please suggest me few ideas
I have written the below code in the constructor of my class so whenever object is created Table is generated and l1 is list of data which i am passing to another UI
input[i] = new MyModel(persons[i].getDateOfRegistration(), persons[i].getFirstName(),
persons[i].getMiddleName(), persons[i].getLastName(), persons[i].getGender(),
persons[i].getDob(), persons[i].getContactNumber(), persons[i].getMaritalStatus(),
persons[i].getAddress(), persons[i].getCountry(), persons[i].getBloodGroup(),
persons[i].getInsuranceDetails().getPolicyHolderName(),
persons[i].getInsuranceDetails().getPolicyNumber(),
persons[i].getInsuranceDetails().getSubscriberName(),
persons[i].getInsuranceDetails().getRelationshipToPatient());
viewer.setInput(input);
table.setHeaderVisible(true);
table.setLinesVisible(true);
GridData gridData = new GridData();
gridData.verticalAlignment = GridData.FILL;
gridData.horizontalSpan = 2;
gridData.grabExcessHorizontalSpace = true;
gridData.grabExcessVerticalSpace = true;
gridData.horizontalAlignment = GridData.FILL;
viewer.getControl().setLayoutData(gridData);
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
StringBuffer sb = new StringBuffer("Selection - ");
int j = 0;
String[] s;
for (Iterator iterator = selection.iterator(); iterator.hasNext();) {
sb.append(iterator.next() + ", ");
System.out.println("Testing::" + sb);
}
System.out.println(sb);
String result[] = new String[18];
List l1 = new ArrayList(100);
String[] parts = sb.toString().split("=");
for (int i = 0; i < parts.length; i++) {
System.out.println("s" + parts[i]);
String[] s1 = parts[i].split(",");
l1.add(s1[0]);
}
SWTPatientRegistrationUpdatePageEventView swtPatientRegistrationUpdatePageEventView = new SWTPatientRegistrationUpdatePageEventView();
swtPatientRegistrationUpdatePageEventView.openParentUpdateShell(l1);
// viewer.refresh();
//flag=false;
//refreshingData(list);
}
});
Make sure we will follow table viewer MVC architecture all the time. Steps we can do to resolve your issue isas follow:
Create proper datastructure(Model Class) to hold the data. and use the same in array which you set in viewer.setInput()
When you click/double click on table row, fetch the data and save it in datastructure created(with new object).
Pass that data structure to your form dialog.
when you are done with update in form. Fill the updated data in new Model object again.
And after form close, pass that model object back to parent.
updated the corresponding array element with object received from Form Dialog and just refresh the tableviewer.
Please let me know if you need some code module. Thanks

GWT Sorting a cell table, probably just something i didn't saw

I've been struggling for the last couple of hour trying to sort a GWT CellTable.
It's really a stupid problem because it's been done here
http://gwt.google.com/samples/Showcase/Showcase.html#!CwCellTable
But I do not understand what I'm missing in the exemple ...
Here is my code I use to create the column:
Column<RemoteCommand, String> nbProducts = new Column<RemoteCommand, String>(
new TextCell()) {
#Override
public String getValue(RemoteCommand object) {
return object.getNumberProduct();
}
};
nbProducts.setSortable(true);
sortHandler.setComparator(nbProducts, new Comparator<RemoteCommand>() {
public int compare(RemoteCommand o1, RemoteCommand o2) {
cellTable.redraw();
return o1.getCommandSize().compareTo(o2.getCommandSize());
// System.out.println(Integer.parseInt(o1.getCommandSize() ) - Integer.parseInt(o2.getCommandSize()));
// return Integer.parseInt(o1.getCommandSize() ) - Integer.parseInt(o2.getCommandSize());
}
});
And here is the declaration of the table itself:
// Add a selection model so we can select cells.
final SelectionModel<RemoteCommand> selectionModel = new MultiSelectionModel<RemoteCommand>(
RemoteCommand.KEY_PROVIDER);
cellTable.setSelectionModel(selectionModel,
DefaultSelectionEventManager.<RemoteCommand> createCheckboxManager());
// Attach a column sort handler to the ListDataProvider to sort the list.
ListHandler<RemoteCommand> sortHandler = new ListHandler<RemoteCommand>(values);
cellTable.addColumnSortHandler(sortHandler);
// Initialize the columns.
initTableColumns(selectionModel, sortHandler);
cellTable.setRowData(values);
help is requierd :)
i guess You've already found the solution, but just to keep it here:
First, create your dataProvider with some known List.
Than feed sortHandler with same List;
and use the list to update data.
Celltable should be set as dataDisplay of the dataProvider:
List myDataList = new ArrayList();
ListDataProvider dataProvider = new ListDataProvider(KEY_PROVIDER);
dataProvider.setList(myDataList);
ListHandler sortHandler = new ListHandler(dataProvider.getList);
//tie provider and table
dataProvider.addDataDisplay(cellTable);
//when you need to update dataprovider
//first do some myDataList cleanup to remove old values
myListData.addAll(values);
//update data displays
dataProvider.refresh();
Consider, you have to always use one and the same List object.