Author: kmorin Date: 2014-01-24 15:54:53 +0100 (Fri, 24 Jan 2014) New Revision: 24 Url: http://forge.codelutin.com/projects/wlo/repository/revisions/24 Log: fixes #4185 Saisie des observations Added: trunk/src/fr/ifremer/wlo/utils/BaseModelArrayAdapter.java Modified: trunk/res/layout/measurement.xml trunk/src/fr/ifremer/wlo/CommercialSpeciesFormActivity.java trunk/src/fr/ifremer/wlo/MainActivity.java trunk/src/fr/ifremer/wlo/measurement/GraphFragment.java trunk/src/fr/ifremer/wlo/measurement/LogsFragment.java trunk/src/fr/ifremer/wlo/measurement/MeasurementActivity.java trunk/src/fr/ifremer/wlo/measurement/TableAdapter.java trunk/src/fr/ifremer/wlo/measurement/TableFragment.java trunk/src/fr/ifremer/wlo/models/CommercialSpeciesModel.java trunk/src/fr/ifremer/wlo/models/MeasurementModel.java trunk/src/fr/ifremer/wlo/models/MeasurementsModel.java trunk/src/fr/ifremer/wlo/models/referentials/Mensuration.java trunk/src/fr/ifremer/wlo/storage/WloSqlOpenHelper.java trunk/src/fr/ifremer/wlo/utils/UIUtils.java Modified: trunk/res/layout/measurement.xml =================================================================== --- trunk/res/layout/measurement.xml 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/res/layout/measurement.xml 2014-01-24 14:54:53 UTC (rev 24) @@ -64,8 +64,7 @@ <EditText android:id="@+id/size" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_weight="1" - android:inputType="number"/> + android:layout_weight="1"/> <Button android:text="+" android:layout_width="wrap_content" Modified: trunk/src/fr/ifremer/wlo/CommercialSpeciesFormActivity.java =================================================================== --- trunk/src/fr/ifremer/wlo/CommercialSpeciesFormActivity.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/CommercialSpeciesFormActivity.java 2014-01-24 14:54:53 UTC (rev 24) @@ -82,6 +82,7 @@ model.setPrecision(null); } }); + precisionSpinner.setSelection(model.getPrecision().ordinal()); Set<String> sortCategories = DataCache.getAllSortCategories(this); initAutoCompleteTextView(R.id.commercial_species_form_sortCategory, CommercialSpeciesModel.COLUMN_SORT_CATEGORY, sortCategories); Modified: trunk/src/fr/ifremer/wlo/MainActivity.java =================================================================== --- trunk/src/fr/ifremer/wlo/MainActivity.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/MainActivity.java 2014-01-24 14:54:53 UTC (rev 24) @@ -36,6 +36,7 @@ protected Button connectButton; protected Button disconnectButton; + protected ProgressDialog dialog; @Override protected void onCreate(Bundle savedInstanceState) { @@ -80,7 +81,7 @@ disconnectButton = (Button) findViewById(R.id.main_disconnect_ichtyometer_button); bigfinDisconnected(); - final ProgressDialog dialog = new ProgressDialog(this); + dialog = new ProgressDialog(this); dialog.setIndeterminate(false); dialog.setCancelable(false); dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); @@ -158,23 +159,6 @@ disconnectButton.setVisibility(View.GONE); } -// @Override -// public synchronized void onResume() { -// super.onResume(); -// -// // Performing this check in onResume() covers the case in which BT was -// // not enabled during onStart(), so we were paused to enable it... -// // onResume() will be called when ACTION_REQUEST_ENABLE activity returns. -// if (mBFCommunicationService != null) { -// // Only if the state is STATE_NONE, do we know that we haven't started already -// if (mBFCommunicationService.getState() == BigFinCommunicationService.STATE_NONE) { -// // Start the Bluetooth chat services -// mBFCommunicationService.start(); -// selectDevice(); -// } -// } -// } - @Override protected Integer getContentView() { return R.layout.main; Modified: trunk/src/fr/ifremer/wlo/measurement/GraphFragment.java =================================================================== --- trunk/src/fr/ifremer/wlo/measurement/GraphFragment.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/measurement/GraphFragment.java 2014-01-24 14:54:53 UTC (rev 24) @@ -2,6 +2,7 @@ import android.content.Intent; import android.os.Bundle; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -9,6 +10,7 @@ import fr.ifremer.wlo.R; import fr.ifremer.wlo.models.MeasurementModel; import fr.ifremer.wlo.models.MeasurementsModel; +import fr.ifremer.wlo.models.referentials.Mensuration; import org.achartengine.ChartFactory; import org.achartengine.GraphicalView; import org.achartengine.chart.BarChart; @@ -55,7 +57,6 @@ mCurrentRenderer.setChartValuesFormat(NumberFormat.getIntegerInstance()); mCurrentRenderer.setColor(getResources().getColor(android.R.color.holo_blue_light)); mCurrentRenderer.setDisplayBoundingPoints(true); - mCurrentRenderer.setChartValuesFormat(NumberFormat.getIntegerInstance()); mCurrentRenderer.setDisplayChartValues(true); mRenderer = new XYMultipleSeriesRenderer(); @@ -98,10 +99,12 @@ int nb = measurements.getMeasurementNb(size); - int index = mCurrentSeries.getIndexForKey(size); + Mensuration.Precision precision = measurements.getPrecision(); + double dSize = (double) size / precision.getUnitDivider(); + int index = mCurrentSeries.getIndexForKey(dSize); mCurrentSeries.remove(index); - mCurrentSeries.add(index, size, nb); + mCurrentSeries.add(index, dSize, nb); mChartView.repaint(); } @@ -112,23 +115,31 @@ int size = measurement.getSize(); int nb = measurements.getMeasurementNb(size); - int count = mCurrentSeries.getItemCount(); - if (size >= count) { - for (int i = count ; i < size ; i++) { + Mensuration.Precision precision = measurements.getPrecision(); + double dSize = (double) size / precision.getUnitDivider(); + double step = (double) precision.getValue() / precision.getUnitDivider(); + double count = mCurrentSeries.getItemCount(); + + if (precision.isDecimal()) { + count = count * precision.getValue() / precision.getUnitDivider(); + } + + if (dSize >= count) { + for (double i = count ; i < dSize ; i = i + step) { mCurrentSeries.add(i, 0); } - mCurrentSeries.add(size, nb); + mCurrentSeries.add(dSize, nb); } else { - int index = mCurrentSeries.getIndexForKey(size); + int index = mCurrentSeries.getIndexForKey(dSize); mCurrentSeries.remove(index); - mCurrentSeries.add(index, size, nb); + mCurrentSeries.add(index, dSize, nb); } - updateAxis(size, nb); + updateAxis(dSize, nb); } - protected void updateAxis(int size, int nb) { + protected void updateAxis(double size, int nb) { mRenderer.setXAxisMin(Math.min(mRenderer.getXAxisMin(), size - 1)); mRenderer.setXAxisMax(Math.max(mRenderer.getXAxisMax(), size + 1)); mRenderer.setYAxisMax(Math.max(mRenderer.getYAxisMax(), nb + 1)); Modified: trunk/src/fr/ifremer/wlo/measurement/LogsFragment.java =================================================================== --- trunk/src/fr/ifremer/wlo/measurement/LogsFragment.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/measurement/LogsFragment.java 2014-01-24 14:54:53 UTC (rev 24) @@ -11,13 +11,21 @@ import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; +import com.google.common.base.Function; import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import fr.ifremer.wlo.R; import fr.ifremer.wlo.models.MeasurementModel; import fr.ifremer.wlo.models.MeasurementsModel; +import fr.ifremer.wlo.storage.DataCache; +import fr.ifremer.wlo.utils.BaseModelArrayAdapter; import fr.ifremer.wlo.utils.UIUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import java.util.Comparator; import java.util.Date; +import java.util.List; /** * @author kmorin <kmorin@codelutin.com> @@ -27,7 +35,7 @@ private static final String TAG = "LogsFragment"; - protected ArrayAdapter<Log> adapter; + protected ArrayAdapter<MeasurementModel> adapter; protected AlertDialog.Builder dialogBuilder; /* Fragment methods */ @@ -44,8 +52,31 @@ super.onActivityCreated(savedInstanceState); Activity activity = getActivity(); - adapter = new ArrayAdapter<Log>(activity, android.R.layout.simple_list_item_1); + adapter = new BaseModelArrayAdapter<MeasurementModel>(activity, android.R.layout.simple_list_item_1, + new Function<MeasurementModel, String>() { + @Override + public String apply(MeasurementModel measurement) { + Context context = getActivity(); + String result = measurement.toString(context,measurements.getPrecision()) + "\n"; + List<Object> cats = Lists.newArrayList(); + Object cat1 = DataCache.getGenderById(context, measurement.getCategory1()); + if (cat1 != null) { + cats.add(cat1); + } + Object cat2 = DataCache.getMaturityById(context, measurement.getCategory2()); + if (cat2 != null) { + cats.add(cat2); + } + Object cat3 = DataCache.getAgeById(context, measurement.getCategory3()); + if (cat3 != null) { + cats.add(cat3); + } + result += StringUtils.join(cats, " - "); + return result; + } + }); + dialogBuilder = new AlertDialog.Builder(activity) .setTitle(R.string.deletion_confirmation_title) .setNegativeButton(android.R.string.cancel, UIUtils.getCancelClickListener()); @@ -56,12 +87,12 @@ logsList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { - final Log log = (Log) parent.getItemAtPosition(position); + final MeasurementModel measurement = (MeasurementModel) parent.getItemAtPosition(position); - dialogBuilder.setMessage(getString(R.string.deletion_confirmation_message, log.toString())) + dialogBuilder.setMessage(getString(R.string.deletion_confirmation_message, + measurement.toString(getActivity(), measurements.getPrecision()))) .setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - MeasurementModel measurement = log.getMeasurement(); measurements.removeMeasurement(measurement); } }) @@ -70,53 +101,28 @@ return true; } }); + + for (MeasurementModel measurement : measurements.getMeasurements().values()) { + onMeasurementAdded(measurements, measurement); + } + adapter.sort(new Comparator<MeasurementModel>() { + @Override + public int compare(MeasurementModel lhs, MeasurementModel rhs) { + return ObjectUtils.compare(rhs.getDate(), lhs.getDate()); + } + }); } /* MeasurementsListener methods */ @Override public void onMeasurementAdded(MeasurementsModel source, MeasurementModel measurement) { - adapter.insert(new Log(measurement), 0); + adapter.insert(measurement, 0); } @Override public void onMeasurementRemoved(MeasurementsModel source, MeasurementModel measurement) { - for (int i = 0 ; i < adapter.getCount() ; i++) { - Log log = adapter.getItem(i); - if (log.getMeasurement().equals(measurement)) { - adapter.remove(log); - break; - } - } + adapter.remove(measurement); } - protected class Log { - - protected MeasurementModel measurement; - protected Date date; - - private Log(MeasurementModel measurement) { - Preconditions.checkNotNull(measurement); - this.measurement = measurement; - date = new Date(); - } - - public MeasurementModel getMeasurement() { - return measurement; - } - - @Override - public String toString() { - Context context = getActivity(); - String dateFormat = UIUtils.getDateFormat(getActivity()) + - " " + getActivity().getString(R.string.fulltime_format); - String result = String.format(dateFormat + " - %2$s - %3$s - %4$s - %5$s", date, - measurement.getSize(), - UIUtils.getStringOrUndefined(measurement.getGender(), context), - UIUtils.getStringOrUndefined(measurement.getMaturity(), context), - UIUtils.getStringOrUndefined(measurement.getAge(), context)); - return result; - } - } - } Modified: trunk/src/fr/ifremer/wlo/measurement/MeasurementActivity.java =================================================================== --- trunk/src/fr/ifremer/wlo/measurement/MeasurementActivity.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/measurement/MeasurementActivity.java 2014-01-24 14:54:53 UTC (rev 24) @@ -7,6 +7,8 @@ import android.os.Bundle; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.widget.DrawerLayout; +import android.text.InputType; +import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -14,11 +16,10 @@ import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.ListView; -import android.widget.RadioButton; -import android.widget.RadioGroup; import android.widget.Spinner; import android.widget.TabHost; import android.widget.TextView; +import com.google.common.base.Function; import com.google.common.collect.Lists; import fr.ifremer.wlo.CommercialSpeciesFormActivity; import fr.ifremer.wlo.MainActivity; @@ -31,8 +32,8 @@ import fr.ifremer.wlo.WloModelEditionActivity; import fr.ifremer.wlo.models.referentials.Age; import fr.ifremer.wlo.models.referentials.Maturity; +import fr.ifremer.wlo.models.referentials.Mensuration; import fr.ifremer.wlo.storage.DataCache; -import fr.ifremer.wlo.storage.WloSqlOpenHelper; import fr.ifremer.wlo.models.BaseModel; import fr.ifremer.wlo.models.CommercialSpeciesModel; import fr.ifremer.wlo.models.LocationModel; @@ -42,11 +43,18 @@ import fr.ifremer.wlo.models.ScientificSpeciesModel; import fr.ifremer.wlo.models.VesselModel; import fr.ifremer.wlo.models.referentials.Gender; +import fr.ifremer.wlo.storage.WloSqlOpenHelper; +import fr.ifremer.wlo.utils.BaseTextWatcher; +import fr.ifremer.wlo.utils.UIUtils; +import org.apache.commons.lang3.ObjectUtils; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.Collection; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Calendar; import java.util.List; +import java.util.Locale; /** * @author kmorin <kmorin@codelutin.com> @@ -63,6 +71,8 @@ protected static final String TABLE_TAB = "table"; protected static final String LOGS_TAB = "logs"; + protected WloSqlOpenHelper soh = new WloSqlOpenHelper(this); + protected TabHost tabs; protected EditText sizeText; protected ActionBarDrawerToggle mDrawerToggle; @@ -101,11 +111,34 @@ scientificSpecies = (ScientificSpeciesModel) getIntent().getSerializableExtra(INTENT_EXTRA_SCIENTIFIC_SPECIES); measurements = new MeasurementsModel(); measurements.setScientificSpecies(scientificSpecies); + + Cursor cursor = soh.getAllMeasurements(scientificSpecies.getId()); + List<MeasurementModel> measurementList = WloSqlOpenHelper.transformCursorIntoCollection(cursor, + new Function<Cursor, MeasurementModel>() { + @Override + public MeasurementModel apply(Cursor cursor) { + return new MeasurementModel(cursor); + } + }); + for (MeasurementModel measurement : measurementList) { + measurements.addMeasurement(measurement); + } } + measurements.addMeasurementsListener(new MeasurementsModel.MeasurementsListener() { + @Override + public void onMeasurementAdded(MeasurementsModel source, MeasurementModel measurement) { + } + + @Override + public void onMeasurementRemoved(MeasurementsModel source, MeasurementModel measurement) { + soh.deleteMeasurement(measurement); + } + }); + commercialSpecies = scientificSpecies.getParent(); + measurements.setPrecision(commercialSpecies.getPrecision()); metier = commercialSpecies.getParent(); vessel = metier.getParent(); - LocationModel location = vessel.getParent(); tabs = (TabHost)findViewById(android.R.id.tabhost); @@ -116,26 +149,54 @@ setupTab(R.id.logs, LOGS_TAB, R.string.logs_tab); sizeText = (EditText) findViewById(R.id.size); + int inputType = InputType.TYPE_CLASS_NUMBER; + if (measurements.getPrecision().isDecimal()) { + inputType |= InputType.TYPE_NUMBER_FLAG_DECIMAL; + } + sizeText.setRawInputType(inputType); + sizeText.addTextChangedListener(new BaseTextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + Log.d(TAG, "beforetextchnage " + s); + } + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + Mensuration.Precision precision = measurements.getPrecision(); + int multiplier = precision.getUnitDivider(); + try { + NumberFormat format = NumberFormat.getInstance(Locale.US); + Number number = format.parse(s.toString()); + double d = number.doubleValue(); + int size = (int)(d * multiplier); + measurement.setSize(size); + + } catch (ParseException e) { + Log.e(TAG, "ParseException ", e); + measurement.setSize(null); + } + } + }); + Spinner genderSpinner = (Spinner) findViewById(R.id.gender_spinner); genderSpinner.setOnItemSelectedListener(this); List<Gender> genders = Lists.newArrayList(DataCache.getAllGenders(this)); - ArrayAdapter<Gender> gendersAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, android.R.id.text1, genders); + ArrayAdapter<Gender> gendersAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, genders); genderSpinner.setAdapter(gendersAdapter); Spinner maturitySpinner = (Spinner) findViewById(R.id.maturity_spinner); maturitySpinner.setOnItemSelectedListener(this); List<Maturity> maturities = Lists.newArrayList(DataCache.getAllMaturities(this)); - ArrayAdapter<Maturity> maturitiesAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, android.R.id.text1, maturities); + ArrayAdapter<Maturity> maturitiesAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, maturities); maturitySpinner.setAdapter(maturitiesAdapter); Spinner ageSpinner = (Spinner) findViewById(R.id.age_spinner); ageSpinner.setOnItemSelectedListener(this); List<Age> ages = Lists.newArrayList(DataCache.getAllAges(this)); - ArrayAdapter<Age> agesAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, android.R.id.text1, ages); + ArrayAdapter<Age> agesAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, ages); ageSpinner.setAdapter(agesAdapter); - initFishMeasurement(10, null); + initFishMeasurement(10 * measurements.getPrecision().getUnitDivider(), null, null, null); DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerList = (ListView) findViewById(R.id.left_drawer); @@ -159,11 +220,12 @@ ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setHomeButtonEnabled(true); - actionBar.setTitle(vessel.toString(this) + " / " + - metier.toString(this) + " / " + - commercialSpecies.toString(this) + " / " + - scientificSpecies.toString(this)); - actionBar.setSubtitle(commercialSpecies.getMeasurementMethod().toString(this)); + actionBar.setTitle(commercialSpecies.toString(this) + " / " + + scientificSpecies.toString(this) + " / " + + commercialSpecies.getMeasurementMethod().toString(this) + " / " + + commercialSpecies.getPrecision()); + actionBar.setSubtitle(vessel.toString(this) + " / " + + metier.toString(this)); } @Override @@ -186,6 +248,7 @@ break; case 3: commercialSpecies = (CommercialSpeciesModel) data.getSerializableExtra(WloModelEditionActivity.INTENT_EXTRA_MODEL); + measurements.setPrecision(commercialSpecies.getPrecision()); break; case 4: scientificSpecies = (ScientificSpeciesModel) data.getSerializableExtra(WloModelEditionActivity.INTENT_EXTRA_MODEL); @@ -214,16 +277,23 @@ } @Override + protected void onDestroy() { + super.onDestroy(); + soh.close(); + } + + @Override public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { + BaseModel selected = (BaseModel) adapterView.getItemAtPosition(i); switch(adapterView.getId()) { case R.id.gender_spinner: - measurement.setGender((Gender) adapterView.getItemAtPosition(i)); + measurement.setCategory1(selected.getId()); break; case R.id.maturity_spinner: - measurement.setMaturity((Maturity) adapterView.getItemAtPosition(i)); + measurement.setCategory2(selected.getId()); break; case R.id.age_spinner: - measurement.setAge((Age) adapterView.getItemAtPosition(i)); + measurement.setCategory3(selected.getId()); break; } } @@ -235,53 +305,78 @@ /* Public methods */ public void incSize(View source) { - measurement.incSize(); + measurement.incSize(measurements.getPrecision().getValue()); } public void decSize(View source) { - measurement.decSize(); + measurement.decSize(measurements.getPrecision().getValue()); } public void addMeasurement(View source) { + measurement.setDate(Calendar.getInstance()); + measurement.roundSize(measurements.getPrecision()); + soh.saveData(measurement); measurements.addMeasurement(measurement); Integer size = measurement.getSize(); - Gender gender = measurement.getGender(); - initFishMeasurement(size, gender); + String cat1 = measurement.getCategory1(); + String cat2 = measurement.getCategory2(); + String cat3 = measurement.getCategory3(); + initFishMeasurement(size, cat1, cat2, cat3); } /* Protected methods */ - protected void initFishMeasurement(Integer size, Gender gender) { + protected void initFishMeasurement(Integer size, String cat1, String cat2, String cat3) { measurement = new MeasurementModel(); measurement.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent event) { String propertyName = event.getPropertyName(); - if (MeasurementModel.SIZE_PROPERTY.equals(propertyName)) { - Integer newValue = (Integer) event.getNewValue(); - sizeText.setText(newValue != null ? newValue.toString() : null); + Object newValue = event.getNewValue(); + switch(propertyName) { + case MeasurementModel.COLUMN_SIZE: + String text = null; + if (newValue != null) { + text = UIUtils.getFormattedSize((Integer) newValue, measurements.getPrecision()); + } + sizeText.setText(text); + break; - } else if (MeasurementModel.GENDER_PROPERTY.equals(propertyName)) { - Gender newValue = (Gender) event.getNewValue(); -// int radioId; -// switch (newValue) { -// case M: -// radioId = R.id.genderMaleRadio; -// break; -// case F: -// radioId = R.id.genderFemaleRadio; -// break; -// default: -// radioId = R.id.genderUndefinedRadio; -// } -// genderGroup.check(radioId); + case MeasurementModel.COLUMN_CATEGORY_1: + Spinner spinner = (Spinner) findViewById(R.id.gender_spinner); + ArrayAdapter adapter = (ArrayAdapter) spinner.getAdapter(); + Object o = DataCache.getGenderById(MeasurementActivity.this, (String) newValue); + int position = adapter.getPosition(o); + spinner.setSelection(position); + break; + + case MeasurementModel.COLUMN_CATEGORY_2: + newValue = event.getNewValue(); + spinner = (Spinner) findViewById(R.id.maturity_spinner); + adapter = (ArrayAdapter) spinner.getAdapter(); + o = DataCache.getMaturityById(MeasurementActivity.this, (String) newValue); + position = adapter.getPosition(o); + spinner.setSelection(position); + break; + + case MeasurementModel.COLUMN_CATEGORY_3: + newValue = event.getNewValue(); + spinner = (Spinner) findViewById(R.id.age_spinner); + adapter = (ArrayAdapter) spinner.getAdapter(); + o = DataCache.getAgeById(MeasurementActivity.this, (String) newValue); + position = adapter.getPosition(o); + spinner.setSelection(position); + break; } } }); measurement.setSize(size); - measurement.setGender(gender); + measurement.setCategory1(cat1); + measurement.setCategory2(cat2); + measurement.setCategory3(cat3); + measurement.setParent(scientificSpecies); } protected void setupTab(int contentId, String tag, int label) { Modified: trunk/src/fr/ifremer/wlo/measurement/TableAdapter.java =================================================================== --- trunk/src/fr/ifremer/wlo/measurement/TableAdapter.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/measurement/TableAdapter.java 2014-01-24 14:54:53 UTC (rev 24) @@ -7,6 +7,8 @@ import android.widget.BaseAdapter; import android.widget.TextView; import fr.ifremer.wlo.R; +import fr.ifremer.wlo.models.referentials.Mensuration; +import fr.ifremer.wlo.utils.UIUtils; import java.util.TreeMap; @@ -18,11 +20,13 @@ private static final String TAG = "TableAdapter"; - protected TreeMap<Integer, Integer> data = new TreeMap<Integer, Integer>(); + protected TreeMap<Integer, Integer> data = new TreeMap<>(); protected Context context; + protected Mensuration.Precision precision; - public TableAdapter(Context context) { + public TableAdapter(Context context, Mensuration.Precision precision) { this.context = context; + this.precision = precision; } /* BaseAdapter methods */ @@ -64,7 +68,7 @@ } Integer size = (Integer) getItem(position); - viewHolder.sizeText.setText(String.valueOf(size)); + viewHolder.sizeText.setText(UIUtils.getFormattedSize(size, precision)); viewHolder.nbText.setText(String.valueOf(data.get(size))); int color; Modified: trunk/src/fr/ifremer/wlo/measurement/TableFragment.java =================================================================== --- trunk/src/fr/ifremer/wlo/measurement/TableFragment.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/measurement/TableFragment.java 2014-01-24 14:54:53 UTC (rev 24) @@ -33,8 +33,12 @@ public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); table = (ListView) getActivity().findViewById(R.id.table_content); - adapter = new TableAdapter(getActivity()); + adapter = new TableAdapter(getActivity(), measurements.getPrecision()); table.setAdapter(adapter); + + for (MeasurementModel measurement : measurements.getMeasurements().values()) { + onMeasurementAdded(measurements, measurement); + } } /* MeasurementsListener methods */ Modified: trunk/src/fr/ifremer/wlo/models/CommercialSpeciesModel.java =================================================================== --- trunk/src/fr/ifremer/wlo/models/CommercialSpeciesModel.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/models/CommercialSpeciesModel.java 2014-01-24 14:54:53 UTC (rev 24) @@ -59,7 +59,9 @@ faoCode = DataCache.getCommercialSpeciesById(context, faoCodeId); String measurementMethodId = cursor.getString(2); measurementMethod = DataCache.getMensurationById(context, measurementMethodId); + Log.d(TAG, cursor.getString(3)); precision = Mensuration.Precision.valueOf(cursor.getString(3)); + Log.d(TAG, precision.toString()); speciesMix = cursor.getShort(4) > 0; sortCategory = cursor.getString(5); String stateId = cursor.getString(6); Modified: trunk/src/fr/ifremer/wlo/models/MeasurementModel.java =================================================================== --- trunk/src/fr/ifremer/wlo/models/MeasurementModel.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/models/MeasurementModel.java 2014-01-24 14:54:53 UTC (rev 24) @@ -1,33 +1,67 @@ package fr.ifremer.wlo.models; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.util.Log; +import fr.ifremer.wlo.R; import fr.ifremer.wlo.models.referentials.Age; import fr.ifremer.wlo.models.referentials.Gender; import fr.ifremer.wlo.models.referentials.Maturity; +import fr.ifremer.wlo.models.referentials.Mensuration; +import fr.ifremer.wlo.storage.DataCache; +import fr.ifremer.wlo.utils.UIUtils; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.Serializable; +import java.util.Calendar; /** * @author kmorin <kmorin@codelutin.com> * @since 0.1 */ -public class MeasurementModel implements Serializable { +public class MeasurementModel extends HierarchicalModel<ScientificSpeciesModel> { - private static final String TAG = "Measurement"; + private static final String TAG = "MeasurementModel"; - public static final String SIZE_PROPERTY = "size"; - public static final String GENDER_PROPERTY = "gender"; - public static final String MATURITY_PROPERTY = "maturity"; - public static final String AGE_PROPERTY = "age"; + public static final String TABLE_NAME = "measurements"; + public static final String COLUMN_SIZE = "size"; + public static final String COLUMN_DATE = "date"; + public static final String COLUMN_CATEGORY_1 = "category1"; + public static final String COLUMN_CATEGORY_2 = "category2"; + public static final String COLUMN_CATEGORY_3 = "category3"; + public static final String COLUMN_SCIENTIFIC_SPECIES_ID = "scientificSpeciesId"; + public static final String[] ALL_COLUMNS = new String[] { + _ID, + COLUMN_SIZE, + COLUMN_DATE, + COLUMN_CATEGORY_1, + COLUMN_CATEGORY_2, + COLUMN_CATEGORY_3, + COLUMN_SCIENTIFIC_SPECIES_ID + }; + @Override + public String getTableName() { + return TABLE_NAME; + } + protected Integer size; - protected Gender gender; - protected Maturity maturity; - protected Age age; + protected Calendar date; + protected String category1; + protected String category2; + protected String category3; - protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(this); + public MeasurementModel() { + } + public MeasurementModel(Cursor cursor) { + super(cursor); + size = cursor.getInt(1); + date = UIUtils.getCalendarFromCursor(cursor, 2); + category1 = cursor.getString(3); + category2 = cursor.getString(4); + category3 = cursor.getString(5); + } + public Integer getSize() { return size; } @@ -35,56 +69,81 @@ public void setSize(Integer size) { Integer oldValue = this.size; this.size = size; - changeSupport.firePropertyChange(SIZE_PROPERTY, oldValue, size); + Log.d(TAG, size + " " + oldValue + " " + size.equals(oldValue)); + changeSupport.firePropertyChange(COLUMN_SIZE, oldValue, size); } - public void incSize() { + public void incSize(int inc) { if (size != null) { - setSize(size + 1); + setSize(size + inc); } } - public void decSize() { + public void decSize(int dec) { if (size != null) { - setSize(size - 1); + setSize(size - dec); } } - public Gender getGender() { - return gender; + public void roundSize(Mensuration.Precision precision) { + if (size == null) { + return; + } + int precisionValue = precision.getValue(); + int roundedSize = (size / precisionValue) * precisionValue; + setSize(roundedSize); } - public void setGender(Gender gender) { - Object oldValue = this.gender; - this.gender = gender; - changeSupport.firePropertyChange(GENDER_PROPERTY, oldValue, gender); + public Calendar getDate() { + return date; } - public Maturity getMaturity() { - return maturity; + public void setDate(Calendar date) { + this.date = date; } - public void setMaturity(Maturity maturity) { - Object oldValue = this.maturity; - this.maturity = maturity; - changeSupport.firePropertyChange(MATURITY_PROPERTY, oldValue, maturity); + public String getCategory1() { + return category1; } - public Age getAge() { - return age; + public void setCategory1(String category1) { + this.category1 = category1; } - public void setAge(Age age) { - Object oldValue = this.age; - this.age = age; - changeSupport.firePropertyChange(AGE_PROPERTY, oldValue, age); + public String getCategory2() { + return category2; } - public void addPropertyChangeListener(PropertyChangeListener listener) { - changeSupport.addPropertyChangeListener(listener); + public void setCategory2(String category2) { + this.category2 = category2; } - public void addPropertyChangeListener(String property, PropertyChangeListener listener) { - changeSupport.addPropertyChangeListener(property, listener); + public String getCategory3() { + return category3; } + + public void setCategory3(String category3) { + this.category3 = category3; + } + + public String toString(Context context, Mensuration.Precision precision) { + String dateFormat = UIUtils.getDateFormat(context) + + " " + context.getString(R.string.fulltime_format); + + String result = String.format(dateFormat, date); + result += " - " + UIUtils.getFormattedSize(size, precision); + return result; + } + + @Override + public ContentValues convertIntoContentValues() { + ContentValues value = super.convertIntoContentValues(); + putValue(value, COLUMN_SIZE, size); + putValue(value, COLUMN_DATE, date != null ? date.getTimeInMillis() : null); + putValue(value, COLUMN_CATEGORY_1, category1); + putValue(value, COLUMN_CATEGORY_2, category2); + putValue(value, COLUMN_CATEGORY_3, category3); + putValue(value, COLUMN_SCIENTIFIC_SPECIES_ID, getParentId()); + return value; + } } Modified: trunk/src/fr/ifremer/wlo/models/MeasurementsModel.java =================================================================== --- trunk/src/fr/ifremer/wlo/models/MeasurementsModel.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/models/MeasurementsModel.java 2014-01-24 14:54:53 UTC (rev 24) @@ -3,6 +3,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; +import fr.ifremer.wlo.models.referentials.Mensuration; import java.io.Serializable; import java.util.ArrayList; @@ -18,6 +19,8 @@ protected ScientificSpeciesModel scientificSpecies; + protected Mensuration.Precision precision; + protected Multimap<Integer, MeasurementModel> measurements = HashMultimap.create(); transient protected List<MeasurementsListener> listeners = new ArrayList<MeasurementsListener>(); @@ -30,6 +33,14 @@ this.scientificSpecies = scientificSpecies; } + public Mensuration.Precision getPrecision() { + return precision; + } + + public void setPrecision(Mensuration.Precision precision) { + this.precision = precision; + } + public Multimap<Integer, MeasurementModel> getMeasurements() { return measurements; } Modified: trunk/src/fr/ifremer/wlo/models/referentials/Mensuration.java =================================================================== --- trunk/src/fr/ifremer/wlo/models/referentials/Mensuration.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/models/referentials/Mensuration.java 2014-01-24 14:54:53 UTC (rev 24) @@ -14,16 +14,28 @@ private static final String TAG = "Mensuration"; public enum Precision { - CM1("1 cm"), - MM5("0.5 cm"), - MM1("1 mm"); + CM1(10, 10, "1 cm"), + MM5(5, 10, "0.5 cm"), + MM1(1, 1, "1 mm"); + private int value; + private int unitDivider; private String label; - private Precision(String label) { + private Precision(int value, int unitDivider, String label) { + this.value = value; + this.unitDivider = unitDivider; this.label = label; } + public int getValue() { + return value; + } + + public int getUnitDivider() { + return unitDivider; + } + public String getLabel() { return label; } @@ -32,6 +44,10 @@ public String toString() { return label; } + + public boolean isDecimal() { + return value % unitDivider > 0; + } } public static final String TABLE_NAME = "ref_mensurations"; Modified: trunk/src/fr/ifremer/wlo/storage/WloSqlOpenHelper.java =================================================================== --- trunk/src/fr/ifremer/wlo/storage/WloSqlOpenHelper.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/storage/WloSqlOpenHelper.java 2014-01-24 14:54:53 UTC (rev 24) @@ -12,6 +12,7 @@ import fr.ifremer.wlo.models.CommercialSpeciesModel; import fr.ifremer.wlo.models.ContextModel; import fr.ifremer.wlo.models.LocationModel; +import fr.ifremer.wlo.models.MeasurementModel; import fr.ifremer.wlo.models.MetierModel; import fr.ifremer.wlo.models.ScientificSpeciesModel; import fr.ifremer.wlo.models.VesselModel; @@ -27,6 +28,7 @@ import fr.ifremer.wlo.models.referentials.State; import fr.ifremer.wlo.models.referentials.Vessel; +import java.util.Collection; import java.util.List; import java.util.Set; import java.util.UUID; @@ -40,7 +42,7 @@ private static final String TAG = "WloOpenHelper"; public static final String DATABASE_NAME = "wlo.db"; - public static final int DATABASE_VERSION = 9; + public static final int DATABASE_VERSION = 10; public static final String TEXT_TYPE = " TEXT"; public static final String BIGINT_TYPE = " BIGINT"; @@ -155,7 +157,24 @@ protected static final String SQL_DELETE_SCIENTIFIC_SPECIES = "DROP TABLE IF EXISTS " + ScientificSpeciesModel.TABLE_NAME; + // MEASUREMENTS + protected static final String SQL_CREATE_MEASUREMENTS = + "CREATE TABLE " + MeasurementModel.TABLE_NAME + " (" + + MeasurementModel._ID + TEXT_TYPE + " PRIMARY KEY" + COMMA_SEP + + MeasurementModel.COLUMN_SIZE + BIGINT_TYPE + COMMA_SEP + + MeasurementModel.COLUMN_DATE + BIGINT_TYPE + COMMA_SEP + + MeasurementModel.COLUMN_CATEGORY_1 + TEXT_TYPE + COMMA_SEP + + MeasurementModel.COLUMN_CATEGORY_2 + TEXT_TYPE + COMMA_SEP + + MeasurementModel.COLUMN_CATEGORY_3 + TEXT_TYPE + COMMA_SEP + + MeasurementModel.COLUMN_SCIENTIFIC_SPECIES_ID + TEXT_TYPE + NOT_NULL + COMMA_SEP + + "FOREIGN KEY(" + MeasurementModel.COLUMN_SCIENTIFIC_SPECIES_ID + ") REFERENCES " + + ScientificSpeciesModel.TABLE_NAME + "(" + ScientificSpeciesModel._ID + ")" + + " )"; + protected static final String SQL_DELETE_MEASUREMENTS = + "DROP TABLE IF EXISTS " + MeasurementModel.TABLE_NAME; + + // Referentials // Ages @@ -320,12 +339,14 @@ db.execSQL(SQL_CREATE_METIERS); db.execSQL(SQL_CREATE_COMMERCIAL_SPECIES); db.execSQL(SQL_CREATE_SCIENTIFIC_SPECIES); + db.execSQL(SQL_CREATE_MEASUREMENTS); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //TODO kmorin 20131129 migrate data before droping the table // models + db.execSQL(SQL_DELETE_MEASUREMENTS); db.execSQL(SQL_DELETE_SCIENTIFIC_SPECIES); db.execSQL(SQL_DELETE_COMMERCIAL_SPECIES); db.execSQL(SQL_DELETE_METIERS); @@ -425,6 +446,23 @@ return cursor; } + //MEASUREMENTS + + public Cursor getAllMeasurements(String scientificSpeciesId) { + SQLiteDatabase db = getReadableDatabase(); + Cursor cursor = db.query(MeasurementModel.TABLE_NAME, MeasurementModel.ALL_COLUMNS, + MeasurementModel.COLUMN_SCIENTIFIC_SPECIES_ID + " = ?", new String[]{ scientificSpeciesId }, + null, null, MeasurementModel.COLUMN_DATE + " ASC"); + return cursor; + } + + public void deleteMeasurement(MeasurementModel measurement) { + if (!measurement.isNew()) { + SQLiteDatabase db = getWritableDatabase(); + db.delete(MeasurementModel.TABLE_NAME, MeasurementModel._ID + " = ?", new String[]{ measurement.getId() }); + } + } + // Referentials public Cursor getAllRefAges() { @@ -527,7 +565,7 @@ saveData(Lists.newArrayList(model)); } - public <M extends BaseModel> void saveData(List<M> models) { + public <M extends BaseModel> void saveData(Collection<M> models) { Preconditions.checkNotNull(models); SQLiteDatabase db = getWritableDatabase(); Added: trunk/src/fr/ifremer/wlo/utils/BaseModelArrayAdapter.java =================================================================== --- trunk/src/fr/ifremer/wlo/utils/BaseModelArrayAdapter.java (rev 0) +++ trunk/src/fr/ifremer/wlo/utils/BaseModelArrayAdapter.java 2014-01-24 14:54:53 UTC (rev 24) @@ -0,0 +1,164 @@ +package fr.ifremer.wlo.utils; + +/* + * Copyright (C) 2006 The Android Open Source Project + * + * 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. + */ + +import android.content.Context; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; +import com.google.common.base.Function; +import fr.ifremer.wlo.models.BaseModel; + +import java.util.List; + +/** + * @author kmorin <kmorin@codelutin.com> + * @since 0.1 + */ +public class BaseModelArrayAdapter<M extends BaseModel> extends ArrayAdapter<M> { + + /** + * The resource indicating what views to inflate to display the content of this + * array adapter. + */ + protected int mResource; + + /** + * If the inflated resource is not a TextView, {@link #mFieldId} is used to find + * a TextView inside the inflated views hierarchy. This field must contain the + * identifier that matches the one defined in the resource file. + */ + protected int mFieldId = 0; + + protected LayoutInflater mInflater; + + /** + * Function to transform object into String + */ + protected Function<M, String> toStringFunction; + + public BaseModelArrayAdapter(Context context, int textViewResourceId, Function<M, String> toStringFunction) { + super(context, textViewResourceId); + init(textViewResourceId, 0, toStringFunction); + } + + public BaseModelArrayAdapter(Context context, int textViewResourceId) { + super(context, textViewResourceId); + init(textViewResourceId, 0, null); + } + + public BaseModelArrayAdapter(Context context, int resource, int textViewResourceId, Function<M, String> toStringFunction) { + super(context, resource, textViewResourceId); + init(resource, textViewResourceId, toStringFunction); + } + + public BaseModelArrayAdapter(Context context, int resource, int textViewResourceId) { + super(context, resource, textViewResourceId); + init(resource, textViewResourceId, null); + } + + public BaseModelArrayAdapter(Context context, int textViewResourceId, M[] objects, Function<M, String> toStringFunction) { + super(context, textViewResourceId, objects); + init(textViewResourceId, 0, toStringFunction); + } + + public BaseModelArrayAdapter(Context context, int textViewResourceId, M[] objects) { + super(context, textViewResourceId, objects); + init(textViewResourceId, 0, null); + } + + public BaseModelArrayAdapter(Context context, int resource, int textViewResourceId, M[] objects, Function<M, String> toStringFunction) { + super(context, resource, textViewResourceId, objects); + init(resource, textViewResourceId, toStringFunction); + } + + public BaseModelArrayAdapter(Context context, int resource, int textViewResourceId, M[] objects) { + super(context, resource, textViewResourceId, objects); + init(resource, textViewResourceId, null); + } + + public BaseModelArrayAdapter(Context context, int textViewResourceId, List<M> objects, Function<M, String> toStringFunction) { + super(context, textViewResourceId, objects); + init(textViewResourceId, 0, toStringFunction); + } + + public BaseModelArrayAdapter(Context context, int textViewResourceId, List<M> objects) { + super(context, textViewResourceId, objects); + init(textViewResourceId, 0, null); + } + + public BaseModelArrayAdapter(Context context, int resource, int textViewResourceId, List<M> objects, Function<M, String> toStringFunction) { + super(context, resource, textViewResourceId, objects); + init(resource, textViewResourceId, toStringFunction); + } + + public BaseModelArrayAdapter(Context context, int resource, int textViewResourceId, List<M> objects) { + super(context, resource, textViewResourceId, objects); + init(resource, textViewResourceId, null); + } + + protected void init(int resource, int textViewResourceId, Function<M, String> toStringFunction) { + mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mResource = resource; + mFieldId = textViewResourceId; + this.toStringFunction = toStringFunction; + } + + public View getView(int position, View convertView, ViewGroup parent) { + return createViewFromResource(position, convertView, parent, mResource); + } + + private View createViewFromResource(int position, View convertView, ViewGroup parent, + int resource) { + View view; + TextView text; + + if (convertView == null) { + view = mInflater.inflate(resource, parent, false); + } else { + view = convertView; + } + + try { + if (mFieldId == 0) { + // If no custom field is assigned, assume the whole resource is a TextView + text = (TextView) view; + } else { + // Otherwise, find the TextView field within the layout + text = (TextView) view.findViewById(mFieldId); + } + } catch (ClassCastException e) { + Log.e("BaseModelArrayAdapter", "You must supply a resource ID for a TextView"); + throw new IllegalStateException( + "BaseModelArrayAdapter requires the resource ID to be a TextView", e); + } + + M item = getItem(position); + String s; + if (toStringFunction != null) { + s = toStringFunction.apply(item); + } else { + s = item.toString(getContext()); + } + text.setText(s); + + return view; + } +} Modified: trunk/src/fr/ifremer/wlo/utils/UIUtils.java =================================================================== --- trunk/src/fr/ifremer/wlo/utils/UIUtils.java 2014-01-24 11:39:51 UTC (rev 23) +++ trunk/src/fr/ifremer/wlo/utils/UIUtils.java 2014-01-24 14:54:53 UTC (rev 24) @@ -5,11 +5,14 @@ import android.content.SharedPreferences; import android.database.Cursor; import android.preference.PreferenceManager; +import com.google.common.base.Preconditions; import fr.ifremer.wlo.R; import fr.ifremer.wlo.models.BaseModel; +import fr.ifremer.wlo.models.referentials.Mensuration; import fr.ifremer.wlo.preferences.ListItemPreference; import java.util.Calendar; +import java.util.Locale; /** * @author kmorin <kmorin@codelutin.com> @@ -85,7 +88,6 @@ return dateFormat; } - public static Calendar getCalendarFromCursor(Cursor cursor, int columnIndex) { Calendar cal; if (cursor.getType(columnIndex) == Cursor.FIELD_TYPE_NULL) { @@ -97,4 +99,22 @@ } return cal; } + + public static String getSizeFormat(Mensuration.Precision precision) { + String sizeFormat; + if (precision == Mensuration.Precision.MM5) { + sizeFormat = "%.1f"; + } else { + sizeFormat = "%.0f"; + } + return sizeFormat; + } + + public static String getFormattedSize(int size, Mensuration.Precision precision) { + Preconditions.checkNotNull(precision); + String format = getSizeFormat(precision); + int divider = precision.getUnitDivider(); + double dSize = (double) size / divider; + return String.format(Locale.US, format, dSize); + } }