/** * Copyright (c) 2002-2013 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.noser.neo4j.android.dbinspector.implementation; import java.util.Formatter; import java.util.List; import org.neo4j.android.client.GraphDatabase; import org.neo4j.android.common.ParcelableNode; import org.neo4j.android.common.ParcelableRelationship; import roboguice.activity.RoboActivity; import roboguice.inject.ContentView; import roboguice.inject.InjectExtra; import roboguice.inject.InjectView; import roboguice.util.Ln; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import com.google.inject.Inject; import com.noser.neo4j.android.dbinspector.R; import com.noser.neo4j.android.dbinspector.base.DBInspectorConstants; import com.noser.neo4j.android.dbinspector.interfaces.IDBManager; @ContentView(R.layout.node_properties_activity) public class NodePropertiesActivity extends RoboActivity { @Inject private Context context; @Inject private IDBManager dbManager; @Inject private LayoutInflater inflater; @InjectExtra(value = DBInspectorConstants.INTENTEXTRA_NODEID) private long nodeId; @InjectView(R.id.nodePropertiesListLayout) private LinearLayout nodePropertiesListLayout; @InjectView(R.id.nodePropertiesTitle) private TextView nodePropertiesTitle; @InjectView(R.id.nodeCreatePropertyButton) ImageButton nodeCreatePropertyButton; @InjectView(R.id.nodeDeleteButton) ImageButton nodeDeleteButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTitle(getResources().getString(R.string.database_title) + " " + dbManager.getCurrentNeo4jDatabaseName()); nodeCreatePropertyButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { askCreateProperty(); } }); nodeDeleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { confirmDeletionOfNode(); } }); Formatter formatter = new Formatter(); formatter.format(getResources().getString(R.string.node_properties_text), nodeId); nodePropertiesTitle.setText(formatter.toString()); formatter.close(); } @Override protected void onResume() { super.onResume(); updateNodePropertiesList(); } private void updateNodePropertiesList() { try { nodePropertiesListLayout.removeAllViews(); GraphDatabase database = dbManager.getCurrentNeo4jDatabase(); database.beginTx(); try { ParcelableNode node = database.getNodeById(nodeId); for (String key : node.getPropertyKeys()) { Object value = node.getProperty(key); addNodePropertiesListItem(key, value); } } finally { database.txFinish(); } } catch (Exception e) { Ln.e(e, "database exception. node id '" + nodeId + "'"); showErrorDialog(); } } private void addNodePropertiesListItem(final String key, final Object value) { View propertyListItem = inflater.inflate(R.layout.property_listitem, null); TextView propertyKeyText = (TextView) propertyListItem.findViewById(R.id.propertyKeyText); propertyKeyText.setText(key); TextView propertyValueText = (TextView) propertyListItem.findViewById(R.id.propertyValueText); propertyValueText.setText("" + value); ImageButton propertyEditButton = (ImageButton) propertyListItem.findViewById(R.id.propertyEditButton); if (value instanceof String) { final String valueString = (String) value; propertyEditButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { askUpdateProperty(key, valueString); } }); } else { propertyEditButton.setEnabled(false); } ImageButton propertyDeleteButton = (ImageButton) propertyListItem.findViewById(R.id.propertyDeleteButton); propertyDeleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { confirmDeletionOfProperty(key, value); } }); nodePropertiesListLayout.addView(propertyListItem); } private void confirmDeletionOfProperty(final String key, final Object value) { AlertDialog dialog = new AlertDialog.Builder(this).create(); dialog.setTitle(R.string.property_delete_title); Formatter formatter = new Formatter(); formatter.format(getResources().getString(R.string.property_delete_from_node_question), key, value, nodeId); dialog.setMessage(formatter.toString()); dialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { try { GraphDatabase database = dbManager.getCurrentNeo4jDatabase(); database.beginTx(); try { ParcelableNode node = database.getNodeById(nodeId); node.removeProperty(key); database.updateNode(node); database.txSuccess(); } finally { database.txFinish(); } } catch (Exception e) { Ln.e(e, "failed to delete property with key '" + key + "' and value '" + value + "' from node with id '" + nodeId + "'."); showErrorDialog(); } } }); dialog.setButton2(getResources().getString(android.R.string.cancel), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); dialog.show(); formatter.close(); } private void showErrorDialog() { AlertDialog dialog = new AlertDialog.Builder(context).create(); dialog.setTitle(R.string.error_title); dialog.setMessage(getResources().getText(R.string.database_error)); dialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); dialog.show(); } private void askCreateProperty() { AlertDialog dialog = new AlertDialog.Builder(this).create(); dialog.setTitle(R.string.property_create_title); View propertyCreateView = inflater.inflate(R.layout.property_create, null); final EditText propertyKeyText = (EditText) propertyCreateView.findViewById(R.id.propertyKeyText); final EditText propertyValueText = (EditText) propertyCreateView.findViewById(R.id.propertyValueText); dialog.setView(propertyCreateView); dialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String key = propertyKeyText.getText().toString(); String value = propertyValueText.getText().toString(); if (!key.isEmpty() && !value.isEmpty()) { createProperty(key, value); } else { showPropertyKeyValueEmptyError(key, value); } } }); dialog.setButton2(getResources().getString(android.R.string.cancel), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); dialog.show(); } private void showPropertyKeyValueEmptyError(String key, String value) { AlertDialog dialog = new AlertDialog.Builder(this).create(); dialog.setTitle(R.string.error_title); Formatter formatter = new Formatter(); formatter.format(getResources().getString(R.string.property_key_or_value_empty_error), key, value); dialog.setMessage(formatter.toString()); dialog.setButton(getResources().getString(android.R.string.yes), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); dialog.show(); formatter.close(); } private void createProperty(String key, String value) { try { GraphDatabase database = dbManager.getCurrentNeo4jDatabase(); database.beginTx(); try { ParcelableNode node = database.getNodeById(nodeId); if (!node.hasProperty(key)) { node.setProperty(key, value); database.updateNode(node); database.txSuccess(); } else { showPropertyAlreadyExistsError(key, value); } } finally { database.txFinish(); } } catch (Exception e) { Ln.e(e, "failed to create new property with key '" + key + "' and value '" + value + "' on node with id '" + nodeId + "'."); showErrorDialog(); } updateNodePropertiesList(); } private void showPropertyAlreadyExistsError(String key, String value) { AlertDialog dialog = new AlertDialog.Builder(this).create(); dialog.setTitle(R.string.error_title); Formatter formatter = new Formatter(); formatter.format(getResources().getString(R.string.property_create_already_exists_on_node_error), key, value, nodeId); dialog.setMessage(formatter.toString()); dialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); dialog.show(); formatter.close(); } private void askUpdateProperty(final String key, String value) { AlertDialog dialog = new AlertDialog.Builder(this).create(); dialog.setTitle(R.string.property_update_title); View propertyEditView = inflater.inflate(R.layout.property_edit, null); final TextView propertyKeyText = (TextView) propertyEditView.findViewById(R.id.propertyKeyText); propertyKeyText.setText(key); final EditText propertyValueText = (EditText) propertyEditView.findViewById(R.id.propertyValueText); propertyValueText.setText(value); dialog.setView(propertyEditView); dialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String value = propertyValueText.getText().toString(); if (!value.isEmpty()) { try { GraphDatabase database = dbManager.getCurrentNeo4jDatabase(); database.beginTx(); try { ParcelableNode node = database.getNodeById(nodeId); node.setProperty(key, value); database.updateNode(node); database.txSuccess(); } finally { database.txFinish(); } } catch (Exception e) { Ln.e(e, "failed to update new property with key '" + key + "' and value '" + value + "' on node with id '" + nodeId + "'."); showErrorDialog(); } } else { showPropertyKeyValueEmptyError(key, value); } updateNodePropertiesList(); } }); dialog.setButton2(getResources().getString(android.R.string.cancel), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); dialog.show(); } private void confirmDeletionOfNode() { AlertDialog dialog = new AlertDialog.Builder(this).create(); dialog.setTitle(R.string.node_delete_title); Formatter formatter = new Formatter(); formatter.format(getResources().getString(R.string.node_delete_question), nodeId); dialog.setMessage(formatter.toString()); dialog.setButton(getResources().getString(android.R.string.yes), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { try { GraphDatabase database = dbManager.getCurrentNeo4jDatabase(); database.beginTx(); try { ParcelableNode node = database.getNodeById(nodeId); ParcelableNode referenceNode = database.getReferenceNode(); if (nodeId != referenceNode.getId()) { List<ParcelableRelationship> relationships = node.getRelationships(); for (ParcelableRelationship relationship : relationships) { database.deleteRelationship(relationship.getId()); } database.deleteNode(nodeId); database.txSuccess(); } else { showCannotDeleteReferenceNodeError(); } } finally { database.txFinish(); } Intent data = new Intent(); data.putExtra(DBInspectorConstants.INTENTEXTRA_NODE_DELETED, true); setResult(RESULT_OK, data); finish(); } catch (Exception e) { Ln.e(e, "failed to delete node with id '" + nodeId + "'."); showErrorDialog(); } } }); dialog.setButton2(getResources().getString(android.R.string.no), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); dialog.show(); formatter.close(); } private void showCannotDeleteReferenceNodeError() { AlertDialog dialog = new AlertDialog.Builder(context).create(); dialog.setTitle(R.string.error_title); dialog.setMessage(getResources().getText(R.string.node_delete_referencenode_error)); dialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); dialog.show(); } }