/* * Copyright (c) 2016 LibreTasks - https://github.com/biotinker/LibreTasks * * This file is free software: you may copy, redistribute 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 file 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/>. * * This file incorporates work covered by the following copyright and * permission notice: /******************************************************************************* * Copyright 2009, 2010 Omnidroid - http://code.google.com/p/omnidroid * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ package libretasks.app.view.simple; import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.text.Html; import android.util.Log; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ContextMenu.ContextMenuInfo; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.AdapterView.AdapterContextMenuInfo; import libretasks.app.R; import libretasks.app.view.simple.model.ModelAction; import libretasks.app.view.simple.model.ModelApplication; import libretasks.app.view.simple.model.ModelAttribute; import libretasks.app.view.simple.model.ModelEvent; import libretasks.app.view.simple.model.ModelItem; import libretasks.app.view.simple.model.ModelRuleAction; import libretasks.app.view.simple.model.ModelRuleFilter; import java.util.List; /** * This activity is used to add multiple filters or actions to a new rule. */ public class ActivityChooseFiltersAndActions extends Activity { // Log tag private static final String TAG = ActivityChooseFiltersAndActions.class.getSimpleName(); // State storage private static final String KEY_STATE = "StateActivityChooseFilters"; private static final String KEY_PREF = "selectedRuleItem"; private SharedPreferences state; /** Request codes for Activity creation */ /** Return code for filter building activities. */ public static final int REQUEST_ADD_FILTER = 0; /** Return code for action building activities. */ public static final int REQUEST_ADD_ACTION = 1; /** Return code for filter editing activities. */ public static final int REQUEST_EDIT_FILTER = 2; /** Return code for action editing activities. */ public static final int REQUEST_EDIT_ACTION = 3; /** Return code for rule name editing activity. */ public static final int REQUEST_SET_RULE_NAME = 4; /** Return code for rule building activity. */ public static final int REQUEST_ADD_FILTERS_AND_ACTIONS = 5; /** Result codes for this activity */ /** Result code for saving a rule successfully. */ public static final int RESULT_RULE_SAVED = 1; // Context Menu Options private static final int MENU_HELP = 0; // Context Menu Options private static final int MENU_EDIT = 0; private static final int MENU_DELETE = 1; private ListView listView; private AdapterRule adapterRule; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_choose_filters_and_actions); // Link our listview with the AdapterRule instance. initializeListView(); // Link up bottom button panel areas. initializeButtonPanel(); // Restore UI state if possible. state = getSharedPreferences(ActivityChooseFiltersAndActions.KEY_STATE, Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE); listView.setItemChecked(state.getInt(KEY_PREF, 0), true); } protected void onPause() { super.onPause(); // Save UI state. SharedPreferences.Editor prefsEditor = state.edit(); prefsEditor.putInt(KEY_PREF, listView.getCheckedItemPosition()); prefsEditor.commit(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_ADD_FILTER: // Did the user construct a valid filter? If so add it to the rule. if (RuleBuilder.instance().getChosenRuleFilter() != null) { // Add the filter to the rule builder and the UI tree. adapterRule.addItemToParentPosition(listView.getCheckedItemPosition(), RuleBuilder .instance().getChosenRuleFilter()); } RuleBuilder.instance().resetFilterPath(); break; case REQUEST_EDIT_FILTER: // Did the user modify a valid filter? If so replace it in the rule. if (RuleBuilder.instance().getChosenRuleFilter() != null) { // Add the filter to the rule builder and the UI tree. adapterRule.replaceItem(listView.getCheckedItemPosition(), RuleBuilder.instance() .getChosenRuleFilter()); } RuleBuilder.instance().resetFilterPath(); break; case REQUEST_ADD_ACTION: // Did the user construct a valid action? If so add it to the rule. if (RuleBuilder.instance().getChosenRuleAction() != null) { // Add the action to the rule builder and the UI tree. adapterRule.addItemToParentPosition(listView.getCheckedItemPosition(), RuleBuilder .instance().getChosenRuleAction()); } RuleBuilder.instance().resetActionPath(); break; case REQUEST_EDIT_ACTION: // Did the user modify a valid action? If so replace it in the rule. if (RuleBuilder.instance().getChosenRuleAction() != null) { // Add the action to the rule builder and the UI tree. adapterRule.replaceItem(listView.getCheckedItemPosition(), RuleBuilder.instance() .getChosenRuleAction()); } RuleBuilder.instance().resetActionPath(); break; case REQUEST_SET_RULE_NAME: if (resultCode != Activity.RESULT_CANCELED) { // Try to save the rule for the user now. // We only get this request code if the user picked // a valid rule name. saveRule(); } break; } } private void initializeListView() { listView = (ListView) findViewById(R.id.activity_choosefiltersandactions_listview); adapterRule = new AdapterRule(this, listView); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView.setAdapter(adapterRule); // Set the adapter to render the rule stored in RuleBuilder. // It may be a brand new rule or a saved rule being edited. adapterRule.setRule(RuleBuilder.instance().getRule()); registerForContextMenu(listView); } /** Create an options menu */ @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(Menu.NONE, MENU_HELP, Menu.NONE, getString(R.string.help)).setIcon( android.R.drawable.ic_menu_help).setAlphabeticShortcut('h'); return super.onCreateOptionsMenu(menu); } /** Called when an item of options menu is clicked */ @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_HELP: help(); return true; } return super.onOptionsItemSelected(item); } private void help() { Builder help = new AlertDialog.Builder(this); help.setIcon(android.R.drawable.ic_menu_help); help.setTitle(R.string.help); help.setMessage(Html.fromHtml(getString(R.string.help_filtersandactions))); help.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { } }); help.show(); } public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); menu.add(ContextMenu.NONE, MENU_EDIT, ContextMenu.NONE, R.string.edit); menu.add(ContextMenu.NONE, MENU_DELETE, ContextMenu.NONE, R.string.delete); } @Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); int selectedItemPosition = info.position; listView.setItemChecked(selectedItemPosition, true); // Set the chosen item as selected switch (item.getItemId()) { case MENU_EDIT: editItem(selectedItemPosition); return true; case MENU_DELETE: confirmDeleteItem(selectedItemPosition); return true; default: return super.onContextItemSelected(item); } } /** * Checks whether the currently chosen event has attributes * * @return true if it has at least one attribute */ private boolean hasAttributes() { ModelEvent event = RuleBuilder.instance().getChosenEvent(); List<ModelAttribute> attributes = UIDbHelperStore.instance().db().getAttributesForEvent(event); return !attributes.isEmpty(); } private void initializeButtonPanel() { Button btnAddFilter = (Button) findViewById(R.id.activity_choosefiltersandactions_btnAddFilter); btnAddFilter.setOnClickListener(listenerBtnClickAddFilter); btnAddFilter.setEnabled(hasAttributes()); Button btnAddAction = (Button) findViewById(R.id.activity_choosefiltersandactions_btnAddAction); btnAddAction.setOnClickListener(listenerBtnClickAddAction); Button btnSaveRule = (Button) findViewById(R.id.activity_choosefiltersandactions_btnSaveRule); btnSaveRule.setOnClickListener(listenerBtnClickSaveRule); LinearLayout llBottomButtons = (LinearLayout) findViewById(R.id.activity_choosefiltersandactions_llBottomButtons); llBottomButtons.setBackgroundColor(getResources().getColor(R.color.layout_button_panel)); } /** * Wipes any UI state saves in {@link:state}. Activities which create this activity should call * this before launching so we appear as a brand new instance. * * @param context * Context of caller. */ public static void resetUI(Context context) { UtilUI.resetSharedPreferences(context, KEY_STATE); } private OnClickListener listenerBtnClickAddFilter = new OnClickListener() { public void onClick(View v) { ModelItem selectedItem = adapterRule.getItem(listView.getCheckedItemPosition()); if ((selectedItem instanceof ModelEvent) || (selectedItem instanceof ModelRuleFilter)) { // Now we present the user with a list of attributes they can // filter on for their chosen root event. showDlgAttributes(); } else { UtilUI.showAlert(v.getContext(), getString(R.string.sorry), getString(R.string.add_filter_alert)); return; } } }; private OnClickListener listenerBtnClickAddAction = new OnClickListener() { public void onClick(View v) { // For actions, we don't check what node the user has selected since they must always go to // the end of the rule tree. showDlgApplications(); } }; private void confirmDeleteItem(final int position) { // Ask the user if they're sure they want to delete this item. new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle( R.string.confirm_item_delete).setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { deleteItem(position); } }).setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Do nothing } }).show(); } private void deleteItem(int position) { ModelItem item = adapterRule.getItem(position); if ((item instanceof ModelRuleFilter) || (item instanceof ModelRuleAction)) { adapterRule.removeItem(position); } else { UtilUI.showAlert(this, getString(R.string.sorry), getString(R.string.select_filter_delete)); } } private void editItem(int position) { ModelItem item = adapterRule.getItem(position); if (item instanceof ModelRuleFilter) { editFilter(position, (ModelRuleFilter) item); } else if (item instanceof ModelRuleAction) { editAction(position, (ModelRuleAction) item); } else { UtilUI.showAlert(this, getString(R.string.sorry), getString(R.string.select_filter_edit)); } } private OnClickListener listenerBtnClickSaveRule = new OnClickListener() { public void onClick(View v) { // After press save, the rule is set to 'Enabled' as default RuleBuilder.instance().getRule().setIsEnabled(true); // Ask the user for a new rule name. // The result will be stored inside RuleBuilder. // When the activity returns, we can continue trying to save the rule. Intent intent = new Intent(); intent.setClass(getApplicationContext(), ActivityDlgRuleName.class); startActivityForResult(intent, REQUEST_SET_RULE_NAME); } }; /** * Starts up the initial activity for adding a new filter. */ private void showDlgAttributes() { // Reset the chosen filter data if left over from a previous run. RuleBuilder.instance().resetFilterPath(); // Launch the activity chain for adding a filter. // We check if the user completed a // filter in onActivityResult. Intent intent = new Intent(); intent.setClass(getApplicationContext(), ActivityDlgAttributes.class); startActivityForResult(intent, REQUEST_ADD_FILTER); } /** * Starts up the initial activity for adding a new action. */ private void showDlgApplications() { // Reset the chosen action data if left over from a previous run. RuleBuilder.instance().resetActionPath(); // Launch the activity chain for adding an action. // We check if the user completed an action in onActivityResult. Intent intent = new Intent(); intent.setClass(getApplicationContext(), ActivityDlgApplications.class); startActivityForResult(intent, REQUEST_ADD_ACTION); } /** * Shortcuts directly to {@link ActivityDlgFilterInput} for editing an existing filter. */ private void editFilter(int position, ModelRuleFilter filter) { // Set the filter data from the existing rule filter instance. RuleBuilder.instance().resetFilterPath(); RuleBuilder.instance().setChosenModelFilter(filter.getModelFilter()); RuleBuilder.instance().setChosenRuleFilterDataOld(filter.getData()); Intent intent = new Intent(); intent.setClass(getApplicationContext(), ActivityDlgFilterInput.class); startActivityForResult(intent, REQUEST_EDIT_FILTER); } /** * Shortcuts directly to {@link ActivityDlgActionInput} for editing an existing action. */ private void editAction(int position, ModelRuleAction ruleAction) { // Set the action data from the existing rule action instance. ModelAction action = ruleAction.getModelAction(); RuleBuilder ruleBuilder = RuleBuilder.instance(); ruleBuilder.resetFilterPath(); ruleBuilder.setChosenModelAction(ruleAction.getModelAction()); ruleBuilder.setChosenRuleActionDataOld(ruleAction.getDatas()); // Set the application in preparation for activities using user accounts ModelApplication app = UIDbHelperStore.instance().db().getApplicationFromAction(action); ruleBuilder.setChosenApplication(app); Intent intent = new Intent(); intent.setClass(getApplicationContext(), ActivityDlgActionInput.class); startActivityForResult(intent, REQUEST_EDIT_ACTION); } /** * Saves the built-up rule inside {@link RuleBuilder} to the database. * */ private void saveRule() { Log.d(TAG, "entered saveRule()"); long newRuleId = 0; try { newRuleId = UIDbHelperStore.instance().db().saveRule(RuleBuilder.instance().getRule()); } catch (IllegalStateException e) { UtilUI.showAlert(this, getString(R.string.sorry), getString(R.string.illegal_state_exception_catch)); Log.e(TAG, "Save Rule Error: Caught Illegal State Exception when saving", e); return; } catch (Exception e) { UtilUI.showAlert(this, getString(R.string.sorry), getString(R.string.error_saving_rule)); Log.e(TAG, "Save Rule Error: Caught an error when saving", e); return; } Log.d(TAG, "New rule saved."); UtilUI.showAlert(this, getString(R.string.save_rule), getString(R.string.rule_saved)); // We have to reload the rule from the database now so that the UI representation // of it is in-sync with the new element IDs assigned during the save operation. RuleBuilder.instance().resetForEditing(UIDbHelperStore.instance().db().loadRule(newRuleId)); Log.d(TAG, "Save Rule: new rule reloaded from db"); adapterRule.setRule(RuleBuilder.instance().getRule()); Log.d(TAG, "Save Rule: new rule set"); setResult(RESULT_RULE_SAVED); finish(); } }