/*******************************************************************************
* This file is part of Zandy.
*
* Zandy is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Zandy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Zandy. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.gimranov.zandy.app;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.gimranov.zandy.app.data.Creator;
import com.gimranov.zandy.app.data.Database;
import com.gimranov.zandy.app.data.Item;
import com.gimranov.zandy.app.task.APIRequest;
import com.gimranov.zandy.app.task.ZoteroAPITask;
/**
* This Activity handles displaying and editing creators. It works almost the same as
* ItemDataActivity and TagActivity, using a simple ArrayAdapter on Bundles with the creator info.
*
* This currently operates by showing the creators for a given item; it could be
* modified some day to show all creators in the database (when they come to be saved
* that way).
*
* @author ajlyon
*
*/
public class CreatorActivity extends ListActivity {
private static final String TAG = "com.gimranov.zandy.app.CreatorActivity";
static final int DIALOG_CREATOR = 3;
static final int DIALOG_CONFIRM_NAVIGATE = 4;
static final int DIALOG_CONFIRM_DELETE = 5;
public Item item;
private Database db;
/**
* For API <= 7, to pass bundles to activities
*/
private Bundle b = new Bundle();
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
db = new Database(this);
/* Get the incoming data from the calling activity */
String itemKey = getIntent().getStringExtra("com.gimranov.zandy.app.itemKey");
Item item = Item.load(itemKey, db);
this.item = item;
this.setTitle("Creators for "+item.getTitle());
ArrayList<Bundle> rows = item.creatorsToBundleArray();
/*
* We use the standard ArrayAdapter, passing in our data as a Bundle.
* Since it's no longer a simple TextView, we need to override getView, but
* we can do that anonymously.
*/
setListAdapter(new ArrayAdapter<Bundle>(this, R.layout.list_data, rows) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row;
// We are reusing views, but we need to initialize it if null
if (null == convertView) {
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.list_data, null);
} else {
row = convertView;
}
/* Our layout has just two fields */
TextView tvLabel = (TextView) row.findViewById(R.id.data_label);
TextView tvContent = (TextView) row.findViewById(R.id.data_content);
tvLabel.setText(Item.localizedStringForString(
getItem(position).getString("creatorType")));
tvContent.setText(getItem(position).getString("name"));
return row;
}
});
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new OnItemClickListener() {
// Warning here because Eclipse can't tell whether my ArrayAdapter is
// being used with the correct parametrization.
@SuppressWarnings("unchecked")
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// If we have a click on an entry, do something...
ArrayAdapter<Bundle> adapter = (ArrayAdapter<Bundle>) parent.getAdapter();
Bundle row = adapter.getItem(position);
/* TODO Rework this logic to open an ItemActivity showing items with this creator
if (row.getString("label").equals("url")) {
row.putString("url", row.getString("content"));
removeDialog(DIALOG_CONFIRM_NAVIGATE);
showDialog(DIALOG_CONFIRM_NAVIGATE, row);
return;
}
if (row.getString("label").equals("DOI")) {
String url = "http://dx.doi.org/"+Uri.encode(row.getString("content"));
row.putString("url", url);
removeDialog(DIALOG_CONFIRM_NAVIGATE);
showDialog(DIALOG_CONFIRM_NAVIGATE, row);
return;
}
*/
Toast.makeText(getApplicationContext(), row.getString("name"),
Toast.LENGTH_SHORT).show();
}
});
/*
* On long click, we bring up an edit dialog.
*/
lv.setOnItemLongClickListener(new OnItemLongClickListener() {
/*
* Same annotation as in onItemClick(..), above.
*/
@SuppressWarnings("unchecked")
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
// If we have a long click on an entry, show an editor
ArrayAdapter<Bundle> adapter = (ArrayAdapter<Bundle>) parent.getAdapter();
Bundle row = adapter.getItem(position);
CreatorActivity.this.b = row;
removeDialog(DIALOG_CREATOR);
showDialog(DIALOG_CREATOR);
return true;
}
});
}
@Override
public void onDestroy() {
if (db != null) db.close();
super.onDestroy();
}
@Override
public void onResume() {
if (db == null) db = new Database(this);
super.onResume();
}
protected Dialog onCreateDialog(int id) {
final String creatorType = b.getString("creatorType");
final int creatorPosition = b.getInt("position");
String name = b.getString("name");
String firstName = b.getString("firstName");
String lastName = b.getString("lastName");
switch (id) {
/* Editor for a creator
*/
case DIALOG_CREATOR:
AlertDialog.Builder builder;
AlertDialog dialog;
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
final View layout = inflater.inflate(R.layout.creator_dialog,
(ViewGroup) findViewById(R.id.layout_root));
TextView textName = (TextView) layout.findViewById(R.id.creator_name);
textName.setText(name);
TextView textFN = (TextView) layout.findViewById(R.id.creator_firstName);
textFN.setText(firstName);
TextView textLN = (TextView) layout.findViewById(R.id.creator_lastName);
textLN.setText(lastName);
CheckBox mode = (CheckBox) layout.findViewById(R.id.creator_mode);
mode.setChecked((firstName == null || firstName.equals(""))
&& (lastName == null || lastName.equals(""))
&& (lastName != null && !name.equals("")));
// Set up the adapter to get creator types
String[] types = Item.localizedCreatorTypesForItemType(item.getType());
// what position are we?
int arrPosition = 0;
String localType = "";
if (creatorType != null) {
localType = Item.localizedStringForString(creatorType);
} else {
// We default to the first possibility when none specified
localType = Item.localizedStringForString(
Item.creatorTypesForItemType(item.getType())[0]);
}
for (int i = 0; i < types.length; i++) {
if (types[i].equals(localType)) {
arrPosition = i;
break;
}
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, types);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner spinner = (Spinner) layout.findViewById(R.id.creator_type);
spinner.setAdapter(adapter);
spinner.setSelection(arrPosition);
builder = new AlertDialog.Builder(this);
builder.setView(layout);
builder.setPositiveButton(getResources().getString(R.string.ok), new OnClickListener(){
@SuppressWarnings("unchecked")
public void onClick(DialogInterface dialog, int whichButton) {
Creator c;
TextView textName = (TextView) layout.findViewById(R.id.creator_name);
TextView textFN = (TextView) layout.findViewById(R.id.creator_firstName);
TextView textLN = (TextView) layout.findViewById(R.id.creator_lastName);
Spinner spinner = (Spinner) layout.findViewById(R.id.creator_type);
CheckBox mode = (CheckBox) layout.findViewById(R.id.creator_mode);
String selected = (String) spinner.getSelectedItem();
// Set up the adapter to get creator types
String[] types = Item.localizedCreatorTypesForItemType(item.getType());
// what position are we?
int typePos = 0;
for (int i = 0; i < types.length; i++) {
if (types[i].equals(selected)) {
typePos = i;
break;
}
}
String realType = Item.creatorTypesForItemType(item.getType())[typePos];
if (mode.isChecked())
c = new Creator(realType, textName.getText().toString(), true);
else
c = new Creator(realType, textFN.getText().toString(), textLN.getText().toString());
Item.setCreator(item.getKey(), c, creatorPosition, db);
item = Item.load(item.getKey(), db);
ArrayAdapter<Bundle> la = (ArrayAdapter<Bundle>) getListAdapter();
la.clear();
for (Bundle b : item.creatorsToBundleArray()) {
la.add(b);
}
la.notifyDataSetChanged();
}
});
builder.setNeutralButton(getResources().getString(R.string.cancel), new OnClickListener(){
public void onClick(DialogInterface dialog, int whichButton) {
// do nothing
}
});
builder.setNegativeButton(getResources().getString(R.string.menu_delete), new OnClickListener(){
@SuppressWarnings("unchecked")
public void onClick(DialogInterface dialog, int whichButton) {
Item.setCreator(item.getKey(), null, creatorPosition, db);
item = Item.load(item.getKey(), db);
ArrayAdapter<Bundle> la = (ArrayAdapter<Bundle>) getListAdapter();
la.clear();
for (Bundle b : item.creatorsToBundleArray()) {
la.add(b);
}
la.notifyDataSetChanged();
}
});
dialog = builder.create();
return dialog;
case DIALOG_CONFIRM_NAVIGATE:
/* dialog = new AlertDialog.Builder(this)
.setTitle("View this online?")
.setPositiveButton("View", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// The behavior for invalid URIs might be nasty, but
// we'll cross that bridge if we come to it.
Uri uri = Uri.parse(content);
startActivity(new Intent(Intent.ACTION_VIEW)
.setData(uri));
}
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// do nothing
}
}).create();
return dialog;*/
return null;
default:
Log.e(TAG, "Invalid dialog requested");
return null;
}
}
/*
* I've been just copying-and-pasting the options menu code from activity to activity.
* It needs to be reworked for some of these activities.
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.zotero_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.do_sync:
if (!ServerCredentials.check(getApplicationContext())) {
Toast.makeText(getApplicationContext(), getResources().getString(R.string.sync_log_in_first),
Toast.LENGTH_SHORT).show();
return true;
}
Log.d(TAG, "Preparing sync requests, starting with present item");
new ZoteroAPITask(getBaseContext()).execute(APIRequest.update(this.item));
Toast.makeText(getApplicationContext(), getResources().getString(R.string.sync_started),
Toast.LENGTH_SHORT).show();
return true;
case R.id.do_new:
Bundle row = new Bundle();
row.putInt("position", -1);
row.putString("itemKey", this.item.getKey());
removeDialog(DIALOG_CREATOR);
this.b = row;
showDialog(DIALOG_CREATOR);
return true;
case R.id.do_prefs:
startActivity(new Intent(this, SettingsActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}