mirror of https://github.com/tasks/tasks
Remove samples
parent
16b149b76d
commit
f5339735f3
@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
** Copyright (c) 2012 Todoroo Inc
|
||||
**
|
||||
** See the file "LICENSE" for the full license governing this code.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.astrid.filter"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
|
||||
<uses-permission android:name="com.todoroo.astrid.READ" />
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name">
|
||||
|
||||
<receiver android:name="com.example.astrid.filter.FilterExposer">
|
||||
<intent-filter>
|
||||
<action android:name="com.todoroo.astrid.REQUEST_FILTERS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
<uses-sdk android:minSdkVersion="3" />
|
||||
|
||||
</manifest>
|
@ -1,7 +0,0 @@
|
||||
Filter Samples
|
||||
|
||||
This project shows you how to create a filter plugin. It involves three files:
|
||||
|
||||
FilterAddon.java - returns your addon, which allows users to turn it on or off
|
||||
FilterExposer.java - returns your filters
|
||||
AndroidManifest.xml - receives Astrid's requests and sends appropriate stuff
|
@ -1,11 +0,0 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-4
|
Binary file not shown.
Before Width: | Height: | Size: 4.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB |
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
** Copyright (c) 2012 Todoroo Inc
|
||||
**
|
||||
** See the file "LICENSE" for the full license governing this code.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hello"
|
||||
/>
|
||||
</LinearLayout>
|
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
** Copyright (c) 2012 Todoroo Inc
|
||||
**
|
||||
** See the file "LICENSE" for the full license governing this code.
|
||||
-->
|
||||
<resources>
|
||||
<string name="hello">Hello World!</string>
|
||||
<string name="app_name">Astrid Filter Samples</string>
|
||||
</resources>
|
@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.example.astrid.filter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* This class identifies the add-on to Astrid so users can re-order their
|
||||
* add-ons or toggle their visibility.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class FilterAddon extends BroadcastReceiver {
|
||||
|
||||
/**
|
||||
* Allows your plugin intents to identify themselves
|
||||
*/
|
||||
static final String IDENTIFIER = "samplefilter"; //$NON-NLS-1$
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// TODO coming in v3.0.0
|
||||
}
|
||||
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.example.astrid.filter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.todoroo.andlib.Order;
|
||||
import com.todoroo.andlib.QueryTemplate;
|
||||
import com.todoroo.astrid.api.AstridApiConstants;
|
||||
import com.todoroo.astrid.api.Filter;
|
||||
import com.todoroo.astrid.api.FilterListHeader;
|
||||
import com.todoroo.astrid.api.FilterListItem;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
|
||||
/**
|
||||
* Exposes Filters when requested
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public final class FilterExposer extends BroadcastReceiver {
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
FilterListItem[] list = new FilterListItem[2];
|
||||
|
||||
list[0] = new FilterListHeader("Sample Filters");
|
||||
|
||||
ContentValues completedValues = new ContentValues();
|
||||
completedValues.put(Task.COMPLETION_DATE.name, Filter.VALUE_NOW);
|
||||
list[1] = new Filter("Completed by Alpha",
|
||||
"Completed by Alpha",
|
||||
new QueryTemplate().where(Task.COMPLETION_DATE.gt(0)).orderBy(Order.asc(Task.TITLE)),
|
||||
completedValues);
|
||||
|
||||
// transmit filter list
|
||||
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, list);
|
||||
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
||||
}
|
||||
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public final class Constants {
|
||||
static final String SELECT = "SELECT";
|
||||
static final String SPACE = " ";
|
||||
static final String AS = "AS";
|
||||
static final String COMMA = ",";
|
||||
static final String FROM = "FROM";
|
||||
static final String ON = "ON";
|
||||
static final String JOIN = "JOIN";
|
||||
static final String ALL = "*";
|
||||
static final String LEFT_PARENTHESIS = "(";
|
||||
static final String RIGHT_PARENTHESIS = ")";
|
||||
static final String AND = "AND";
|
||||
static final String BETWEEN = "BETWEEN";
|
||||
static final String LIKE = "LIKE";
|
||||
static final String OR = "OR";
|
||||
static final String ORDER_BY = "ORDER BY";
|
||||
static final String GROUP_BY = "GROUP BY";
|
||||
static final String WHERE = "WHERE";
|
||||
public static final String EXISTS = "EXISTS";
|
||||
public static final String NOT = "NOT";
|
||||
public static final String LIMIT = "LIMIT";
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import static com.todoroo.andlib.Constants.AND;
|
||||
import static com.todoroo.andlib.Constants.EXISTS;
|
||||
import static com.todoroo.andlib.Constants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.Constants.NOT;
|
||||
import static com.todoroo.andlib.Constants.OR;
|
||||
import static com.todoroo.andlib.Constants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.Constants.SPACE;
|
||||
|
||||
public abstract class Criterion {
|
||||
protected final Operator operator;
|
||||
|
||||
Criterion(Operator operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public static Criterion all = new Criterion(Operator.exists) {
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(1);
|
||||
}
|
||||
};
|
||||
|
||||
public static Criterion none = new Criterion(Operator.exists) {
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(0);
|
||||
}
|
||||
};
|
||||
|
||||
public static Criterion and(final Criterion criterion, final Criterion... criterions) {
|
||||
return new Criterion(Operator.and) {
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(criterion);
|
||||
for (Criterion c : criterions) {
|
||||
sb.append(SPACE).append(AND).append(SPACE).append(c);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Criterion or(final Criterion criterion, final Criterion... criterions) {
|
||||
return new Criterion(Operator.or) {
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(criterion);
|
||||
for (Criterion c : criterions) {
|
||||
sb.append(SPACE).append(OR).append(SPACE).append(c.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Criterion exists(final Query query) {
|
||||
return new Criterion(Operator.exists) {
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(EXISTS).append(SPACE).append(LEFT_PARENTHESIS).append(query).append(RIGHT_PARENTHESIS);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Criterion not(final Criterion criterion) {
|
||||
return new Criterion(Operator.not) {
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(NOT).append(SPACE);
|
||||
criterion.populate(sb);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract void populate(StringBuilder sb);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(LEFT_PARENTHESIS);
|
||||
populate(builder);
|
||||
builder.append(RIGHT_PARENTHESIS);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import static com.todoroo.andlib.Constants.AS;
|
||||
import static com.todoroo.andlib.Constants.SPACE;
|
||||
|
||||
public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
|
||||
protected String alias;
|
||||
protected final String expression;
|
||||
|
||||
protected DBObject(String expression){
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T as(String newAlias) {
|
||||
try {
|
||||
T clone = (T) clone();
|
||||
clone.alias = newAlias;
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasAlias() {
|
||||
return alias != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
DBObject<?> dbObject = (DBObject<?>) o;
|
||||
|
||||
if (alias != null ? !alias.equals(dbObject.alias) : dbObject.alias != null) return false;
|
||||
if (expression != null ? !expression.equals(dbObject.expression) : dbObject.expression != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = alias != null ? alias.hashCode() : 0;
|
||||
result = 31 * result + (expression != null ? expression.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
if (hasAlias()) {
|
||||
return alias;
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
public final String toStringInSelect() {
|
||||
StringBuilder sb = new StringBuilder(expression);
|
||||
if (hasAlias()) {
|
||||
sb.append(SPACE).append(AS).append(SPACE).append(alias);
|
||||
} else {
|
||||
int pos = expression.indexOf('.');
|
||||
if(pos > 0)
|
||||
sb.append(SPACE).append(AS).append(SPACE).append(expression.substring(pos + 1));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
|
||||
public class DateUtilities {
|
||||
|
||||
/* ======================================================================
|
||||
* ============================================================ long time
|
||||
* ====================================================================== */
|
||||
|
||||
/** Convert unixtime into date */
|
||||
public static final Date unixtimeToDate(long millis) {
|
||||
if(millis == 0)
|
||||
return null;
|
||||
return new Date(millis);
|
||||
}
|
||||
|
||||
/** Convert date into unixtime */
|
||||
public static final long dateToUnixtime(Date date) {
|
||||
if(date == null)
|
||||
return 0;
|
||||
return date.getTime();
|
||||
}
|
||||
|
||||
/** Returns unixtime for current time */
|
||||
public static final long now() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/** Returns unixtime one month from now */
|
||||
public static final long oneMonthFromNow() {
|
||||
Date date = new Date();
|
||||
date.setMonth(date.getMonth() + 1);
|
||||
return date.getTime();
|
||||
}
|
||||
|
||||
/** Represents a single hour */
|
||||
public static long ONE_HOUR = 3600000L;
|
||||
|
||||
/** Represents a single day */
|
||||
public static long ONE_DAY = 24 * ONE_HOUR;
|
||||
|
||||
/** Represents a single week */
|
||||
public static long ONE_WEEK = 7 * ONE_DAY;
|
||||
|
||||
/* ======================================================================
|
||||
* =========================================================== formatters
|
||||
* ====================================================================== */
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public static boolean is24HourFormat(Context context) {
|
||||
String value = android.provider.Settings.System.getString(context.getContentResolver(),
|
||||
android.provider.Settings.System.TIME_12_24);
|
||||
boolean b24 = !(value == null || value.equals("12"));
|
||||
return b24;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return time format (hours and minutes)
|
||||
*/
|
||||
public static SimpleDateFormat getTimeFormat(Context context) {
|
||||
String value = getTimeFormatString(context);
|
||||
return new SimpleDateFormat(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string used for time formatting
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
private static String getTimeFormatString(Context context) {
|
||||
String value;
|
||||
if (is24HourFormat(context)) {
|
||||
value = "H:mm";
|
||||
} else {
|
||||
value = "h:mm a";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string used for date formatting
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
private static String getDateFormatString(Context context) {
|
||||
String value = android.provider.Settings.System.getString(context.getContentResolver(),
|
||||
android.provider.Settings.System.DATE_FORMAT);
|
||||
if (value == null) {
|
||||
// united states, you are special
|
||||
if (Locale.US.equals(Locale.getDefault())
|
||||
|| Locale.CANADA.equals(Locale.getDefault()))
|
||||
value = "MMM d yyyy";
|
||||
else
|
||||
value = "d MMM yyyy";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return date format (month, day, year)
|
||||
*/
|
||||
public static SimpleDateFormat getDateFormat(Context context) {
|
||||
return new SimpleDateFormat(getDateFormatString(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return date format as getDateFormat with weekday
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public static SimpleDateFormat getDateFormatWithWeekday(Context context) {
|
||||
return new SimpleDateFormat("EEE, " + getDateFormatString(context));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return date with time at the end
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public static SimpleDateFormat getDateWithTimeFormat(Context context) {
|
||||
return new SimpleDateFormat(getDateFormatString(context) + " " +
|
||||
getTimeFormatString(context));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return formatted date (will contain month, day, year)
|
||||
*/
|
||||
public static String getFormattedDate(Context context, Date date) {
|
||||
return getDateFormat(context).format(date);
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
public class EqCriterion extends UnaryCriterion {
|
||||
EqCriterion(Field field, Object value) {
|
||||
super(field, Operator.eq, value);
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import static com.todoroo.andlib.Constants.AND;
|
||||
import static com.todoroo.andlib.Constants.BETWEEN;
|
||||
import static com.todoroo.andlib.Constants.COMMA;
|
||||
import static com.todoroo.andlib.Constants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.Constants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.Constants.SPACE;
|
||||
|
||||
public class Field extends DBObject<Field> {
|
||||
|
||||
protected Field(String expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
public static Field field(String expression) {
|
||||
return new Field(expression);
|
||||
}
|
||||
|
||||
public Criterion eq(Object value) {
|
||||
if(value == null)
|
||||
return UnaryCriterion.isNull(this);
|
||||
return UnaryCriterion.eq(this, value);
|
||||
}
|
||||
|
||||
public Criterion neq(Object value) {
|
||||
if(value == null)
|
||||
return UnaryCriterion.isNotNull(this);
|
||||
return UnaryCriterion.neq(this, value);
|
||||
}
|
||||
|
||||
public Criterion gt(Object value) {
|
||||
return UnaryCriterion.gt(this, value);
|
||||
}
|
||||
|
||||
public Criterion lt(final Object value) {
|
||||
return UnaryCriterion.lt(this, value);
|
||||
}
|
||||
|
||||
public Criterion isNull() {
|
||||
return UnaryCriterion.isNull(this);
|
||||
}
|
||||
|
||||
public Criterion isNotNull() {
|
||||
return UnaryCriterion.isNotNull(this);
|
||||
}
|
||||
|
||||
public Criterion between(final Object lower, final Object upper) {
|
||||
final Field field = this;
|
||||
return new Criterion(null) {
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(field).append(SPACE).append(BETWEEN).append(SPACE).append(lower).append(SPACE).append(AND)
|
||||
.append(SPACE).append(upper);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Criterion like(final String value) {
|
||||
return UnaryCriterion.like(this, value);
|
||||
}
|
||||
|
||||
public <T> Criterion in(final T... value) {
|
||||
final Field field = this;
|
||||
return new Criterion(Operator.in) {
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS);
|
||||
for (T t : value) {
|
||||
sb.append(t.toString()).append(COMMA);
|
||||
}
|
||||
sb.deleteCharAt(sb.length() - 1).append(RIGHT_PARENTHESIS);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Criterion in(final Query query) {
|
||||
final Field field = this;
|
||||
return new Criterion(Operator.in) {
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS).append(query)
|
||||
.append(RIGHT_PARENTHESIS);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public final class Functions {
|
||||
|
||||
public static String caseStatement(Criterion when, Object ifTrue, Object ifFalse) {
|
||||
return new StringBuilder("(CASE WHEN ").
|
||||
append(when.toString()).append(" THEN ").append(value(ifTrue)).
|
||||
append(" ELSE ").append(value(ifFalse)).append(" END)").toString();
|
||||
}
|
||||
|
||||
private static String value(Object value) {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
public static Field upper(Field title) {
|
||||
return new Field("UPPER(" + title.toString() + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SQL now (in milliseconds)
|
||||
*/
|
||||
public static Field now() {
|
||||
return new Field("(strftime('%s','now')*1000)");
|
||||
}
|
||||
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GroupBy {
|
||||
private List<Field> fields = new ArrayList<Field>();
|
||||
|
||||
public static GroupBy groupBy(Field field) {
|
||||
GroupBy groupBy = new GroupBy();
|
||||
groupBy.fields.add(field);
|
||||
return groupBy;
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import static com.todoroo.andlib.Constants.JOIN;
|
||||
import static com.todoroo.andlib.Constants.ON;
|
||||
import static com.todoroo.andlib.Constants.SPACE;
|
||||
|
||||
public class Join {
|
||||
private final SqlTable joinTable;
|
||||
private final JoinType joinType;
|
||||
private final Criterion[] criterions;
|
||||
|
||||
private Join(SqlTable table, JoinType joinType, Criterion... criterions) {
|
||||
joinTable = table;
|
||||
this.joinType = joinType;
|
||||
this.criterions = criterions;
|
||||
}
|
||||
|
||||
public static Join inner(SqlTable expression, Criterion... criterions) {
|
||||
return new Join(expression, JoinType.INNER, criterions);
|
||||
}
|
||||
|
||||
public static Join left(SqlTable table, Criterion... criterions) {
|
||||
return new Join(table, JoinType.LEFT, criterions);
|
||||
}
|
||||
|
||||
public static Join right(SqlTable table, Criterion... criterions) {
|
||||
return new Join(table, JoinType.RIGHT, criterions);
|
||||
}
|
||||
|
||||
public static Join out(SqlTable table, Criterion... criterions) {
|
||||
return new Join(table, JoinType.OUT, criterions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(joinType).append(SPACE).append(JOIN).append(SPACE).append(joinTable).append(SPACE).append(ON);
|
||||
for (Criterion criterion : criterions) {
|
||||
sb.append(SPACE).append(criterion);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
public enum JoinType {
|
||||
INNER, LEFT, RIGHT, OUT
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import static com.todoroo.andlib.Constants.SPACE;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public final class Operator {
|
||||
|
||||
private final String operator;
|
||||
public static final Operator eq = new Operator("=");
|
||||
public static final Operator neq = new Operator("<>");
|
||||
public static final Operator isNull = new Operator("IS NULL");
|
||||
public static final Operator isNotNull = new Operator("IS NOT NULL");
|
||||
public static final Operator gt = new Operator(">");
|
||||
public static final Operator lt = new Operator("<");
|
||||
public static final Operator gte = new Operator(">=");
|
||||
public static final Operator lte = new Operator("<=");
|
||||
public static final Operator and = new Operator("AND");
|
||||
public static final Operator or = new Operator("OR");
|
||||
public static final Operator not = new Operator("NOT");
|
||||
public static final Operator exists = new Operator("EXISTS");
|
||||
public static final Operator like = new Operator("LIKE");
|
||||
public static final Operator in = new Operator("IN");
|
||||
|
||||
private static final Map<Operator, Operator> contraryRegistry = new HashMap<Operator, Operator>();
|
||||
|
||||
static {
|
||||
contraryRegistry.put(eq, neq);
|
||||
contraryRegistry.put(neq, eq);
|
||||
contraryRegistry.put(isNull, isNotNull);
|
||||
contraryRegistry.put(isNotNull, isNull);
|
||||
contraryRegistry.put(gt, lte);
|
||||
contraryRegistry.put(lte, gt);
|
||||
contraryRegistry.put(lt, gte);
|
||||
contraryRegistry.put(gte, lt);
|
||||
}
|
||||
|
||||
private Operator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public Operator getContrary() {
|
||||
if(!contraryRegistry.containsKey(this)){
|
||||
Operator opposite = new Operator(not.toString() + SPACE + this.toString());
|
||||
contraryRegistry.put(this, opposite);
|
||||
contraryRegistry.put(opposite, this);
|
||||
}
|
||||
return contraryRegistry.get(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.operator.toString();
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import static com.todoroo.andlib.Constants.SPACE;
|
||||
|
||||
public class Order {
|
||||
private final Object expression;
|
||||
private final OrderType orderType;
|
||||
|
||||
private Order(Object expression) {
|
||||
this(expression, OrderType.ASC);
|
||||
}
|
||||
|
||||
private Order(Object expression, OrderType orderType) {
|
||||
this.expression = expression;
|
||||
this.orderType = orderType;
|
||||
}
|
||||
|
||||
public static Order asc(Object expression) {
|
||||
return new Order(expression);
|
||||
}
|
||||
|
||||
public static Order desc(Object expression) {
|
||||
return new Order(expression, OrderType.DESC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return expression + SPACE + orderType;
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
public enum OrderType {
|
||||
DESC, ASC
|
||||
}
|
@ -1,197 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import static com.todoroo.andlib.Constants.ALL;
|
||||
import static com.todoroo.andlib.Constants.COMMA;
|
||||
import static com.todoroo.andlib.Constants.FROM;
|
||||
import static com.todoroo.andlib.Constants.GROUP_BY;
|
||||
import static com.todoroo.andlib.Constants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.Constants.ORDER_BY;
|
||||
import static com.todoroo.andlib.Constants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.Constants.SELECT;
|
||||
import static com.todoroo.andlib.Constants.SPACE;
|
||||
import static com.todoroo.andlib.Constants.WHERE;
|
||||
import static com.todoroo.andlib.SqlTable.table;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.todoroo.astrid.data.Property;
|
||||
|
||||
public final class Query {
|
||||
|
||||
private SqlTable table;
|
||||
private String queryTemplate = null;
|
||||
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
|
||||
private final ArrayList<Field> fields = new ArrayList<Field>();
|
||||
private final ArrayList<Join> joins = new ArrayList<Join>();
|
||||
private final ArrayList<Field> groupBies = new ArrayList<Field>();
|
||||
private final ArrayList<Order> orders = new ArrayList<Order>();
|
||||
private final ArrayList<Criterion> havings = new ArrayList<Criterion>();
|
||||
|
||||
private Query(Field... fields) {
|
||||
this.fields.addAll(asList(fields));
|
||||
}
|
||||
|
||||
public static Query select(Field... fields) {
|
||||
return new Query(fields);
|
||||
}
|
||||
|
||||
public Query from(SqlTable fromTable) {
|
||||
this.table = fromTable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Query join(Join... join) {
|
||||
joins.addAll(asList(join));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Query where(Criterion criterion) {
|
||||
criterions.add(criterion);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Query groupBy(Field... groupBy) {
|
||||
groupBies.addAll(asList(groupBy));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Query orderBy(Order... order) {
|
||||
orders.addAll(asList(order));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Query appendSelectFields(Property<?>... selectFields) {
|
||||
this.fields.addAll(asList(selectFields));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o || !(o == null || getClass() != o.getClass()) && this.toString().equals(o.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
visitSelectClause(sql);
|
||||
visitFromClause(sql);
|
||||
|
||||
if(queryTemplate == null) {
|
||||
visitJoinClause(sql);
|
||||
visitWhereClause(sql);
|
||||
visitGroupByClause(sql);
|
||||
visitOrderByClause(sql);
|
||||
} else {
|
||||
if(joins.size() > 0 || groupBies.size() > 0 || orders.size() > 0 ||
|
||||
havings.size() > 0)
|
||||
throw new IllegalStateException("Can't have extras AND query template"); //$NON-NLS-1$
|
||||
sql.append(queryTemplate);
|
||||
}
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
private void visitOrderByClause(StringBuilder sql) {
|
||||
if (orders.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append(ORDER_BY);
|
||||
for (Order order : orders) {
|
||||
sql.append(SPACE).append(order).append(COMMA);
|
||||
}
|
||||
sql.deleteCharAt(sql.length() - 1).append(SPACE);
|
||||
}
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
private void visitGroupByClause(StringBuilder sql) {
|
||||
if (groupBies.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append(GROUP_BY);
|
||||
for (Field groupBy : groupBies) {
|
||||
sql.append(SPACE).append(groupBy).append(COMMA);
|
||||
}
|
||||
sql.deleteCharAt(sql.length() - 1).append(SPACE);
|
||||
if (havings.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append("HAVING");
|
||||
for (Criterion havingCriterion : havings) {
|
||||
sql.append(SPACE).append(havingCriterion).append(COMMA);
|
||||
}
|
||||
sql.deleteCharAt(sql.length() - 1).append(SPACE);
|
||||
}
|
||||
|
||||
private void visitWhereClause(StringBuilder sql) {
|
||||
if (criterions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append(WHERE);
|
||||
for (Criterion criterion : criterions) {
|
||||
sql.append(SPACE).append(criterion).append(SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitJoinClause(StringBuilder sql) {
|
||||
for (Join join : joins) {
|
||||
sql.append(join).append(SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitFromClause(StringBuilder sql) {
|
||||
if (table == null) {
|
||||
return;
|
||||
}
|
||||
sql.append(FROM).append(SPACE).append(table).append(SPACE);
|
||||
}
|
||||
|
||||
private void visitSelectClause(StringBuilder sql) {
|
||||
sql.append(SELECT).append(SPACE);
|
||||
if (fields.isEmpty()) {
|
||||
sql.append(ALL).append(SPACE);
|
||||
return;
|
||||
}
|
||||
for (Field field : fields) {
|
||||
sql.append(field.toStringInSelect()).append(COMMA);
|
||||
}
|
||||
sql.deleteCharAt(sql.length() - 1).append(SPACE);
|
||||
}
|
||||
|
||||
public SqlTable as(String alias) {
|
||||
return table(LEFT_PARENTHESIS + this.toString() + RIGHT_PARENTHESIS).as(alias);
|
||||
}
|
||||
|
||||
public Query having(Criterion criterion) {
|
||||
this.havings.add(criterion);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of fields returned by this query
|
||||
* @return
|
||||
*/
|
||||
public Property<?>[] getFields() {
|
||||
return fields.toArray(new Property<?>[fields.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the SQL query template (comes after the "from")
|
||||
* @param sqlQuery
|
||||
* @return
|
||||
*/
|
||||
public Query withQueryTemplate(String template) {
|
||||
queryTemplate = template;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import static com.todoroo.andlib.Constants.COMMA;
|
||||
import static com.todoroo.andlib.Constants.GROUP_BY;
|
||||
import static com.todoroo.andlib.Constants.LIMIT;
|
||||
import static com.todoroo.andlib.Constants.ORDER_BY;
|
||||
import static com.todoroo.andlib.Constants.SPACE;
|
||||
import static com.todoroo.andlib.Constants.WHERE;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Query Template returns a bunch of criteria that allows a query to be
|
||||
* constructed
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public final class QueryTemplate {
|
||||
|
||||
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
|
||||
private final ArrayList<Join> joins = new ArrayList<Join>();
|
||||
private final ArrayList<Field> groupBies = new ArrayList<Field>();
|
||||
private final ArrayList<Order> orders = new ArrayList<Order>();
|
||||
private final ArrayList<Criterion> havings = new ArrayList<Criterion>();
|
||||
private Integer limit = null;
|
||||
|
||||
public QueryTemplate join(Join... join) {
|
||||
joins.addAll(asList(join));
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryTemplate where(Criterion criterion) {
|
||||
criterions.add(criterion);
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryTemplate groupBy(Field... groupBy) {
|
||||
groupBies.addAll(asList(groupBy));
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryTemplate orderBy(Order... order) {
|
||||
orders.addAll(asList(order));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
visitJoinClause(sql);
|
||||
visitWhereClause(sql);
|
||||
visitGroupByClause(sql);
|
||||
visitOrderByClause(sql);
|
||||
if(limit != null)
|
||||
sql.append(LIMIT).append(SPACE).append(limit);
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
private void visitOrderByClause(StringBuilder sql) {
|
||||
if (orders.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append(ORDER_BY);
|
||||
for (Order order : orders) {
|
||||
sql.append(SPACE).append(order).append(COMMA);
|
||||
}
|
||||
sql.deleteCharAt(sql.length() - 1).append(SPACE);
|
||||
}
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
private void visitGroupByClause(StringBuilder sql) {
|
||||
if (groupBies.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append(GROUP_BY);
|
||||
for (Field groupBy : groupBies) {
|
||||
sql.append(SPACE).append(groupBy).append(COMMA);
|
||||
}
|
||||
sql.deleteCharAt(sql.length() - 1).append(SPACE);
|
||||
if (havings.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append("HAVING");
|
||||
for (Criterion havingCriterion : havings) {
|
||||
sql.append(SPACE).append(havingCriterion).append(COMMA);
|
||||
}
|
||||
sql.deleteCharAt(sql.length() - 1).append(SPACE);
|
||||
}
|
||||
|
||||
private void visitWhereClause(StringBuilder sql) {
|
||||
if (criterions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sql.append(WHERE);
|
||||
for (Criterion criterion : criterions) {
|
||||
sql.append(SPACE).append(criterion).append(SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitJoinClause(StringBuilder sql) {
|
||||
for (Join join : joins) {
|
||||
sql.append(join).append(SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
public QueryTemplate having(Criterion criterion) {
|
||||
this.havings.add(criterion);
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryTemplate limit(int limitValue) {
|
||||
this.limit = limitValue;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
public class SqlTable extends DBObject<SqlTable> {
|
||||
|
||||
protected SqlTable(String expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
public static SqlTable table(String table) {
|
||||
return new SqlTable(table);
|
||||
}
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
protected String fieldExpression(String fieldName) {
|
||||
if (hasAlias()) {
|
||||
return alias + "." + fieldName;
|
||||
}
|
||||
return expression+"."+fieldName;
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.andlib;
|
||||
|
||||
import static com.todoroo.andlib.Constants.SPACE;
|
||||
|
||||
public class UnaryCriterion extends Criterion {
|
||||
protected final Field expression;
|
||||
protected final Object value;
|
||||
|
||||
UnaryCriterion(Field expression, Operator operator, Object value) {
|
||||
super(operator);
|
||||
this.expression = expression;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(StringBuilder sb) {
|
||||
beforePopulateOperator(sb);
|
||||
populateOperator(sb);
|
||||
afterPopulateOperator(sb);
|
||||
}
|
||||
|
||||
public static Criterion eq(Field expression, Object value) {
|
||||
return new UnaryCriterion(expression, Operator.eq, value);
|
||||
}
|
||||
|
||||
protected void beforePopulateOperator(StringBuilder sb) {
|
||||
sb.append(expression);
|
||||
}
|
||||
|
||||
protected void populateOperator(StringBuilder sb) {
|
||||
sb.append(operator);
|
||||
}
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
protected void afterPopulateOperator(StringBuilder sb) {
|
||||
if(value == null)
|
||||
return;
|
||||
else if(value instanceof String)
|
||||
sb.append("'").append(sanitize((String) value)).append("'");
|
||||
else
|
||||
sb.append(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the given input for SQL
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public static String sanitize(String input) {
|
||||
return input.replace("\\", "\\\\").replace("'", "\\'");
|
||||
}
|
||||
|
||||
public static Criterion neq(Field field, Object value) {
|
||||
return new UnaryCriterion(field, Operator.neq, value);
|
||||
}
|
||||
|
||||
public static Criterion gt(Field field, Object value) {
|
||||
return new UnaryCriterion(field, Operator.gt, value);
|
||||
}
|
||||
|
||||
public static Criterion lt(Field field, Object value) {
|
||||
return new UnaryCriterion(field, Operator.lt, value);
|
||||
}
|
||||
|
||||
public static Criterion isNull(Field field) {
|
||||
return new UnaryCriterion(field, Operator.isNull, null) {
|
||||
@Override
|
||||
protected void populateOperator(StringBuilder sb) {
|
||||
sb.append(SPACE).append(operator);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Criterion isNotNull(Field field) {
|
||||
return new UnaryCriterion(field, Operator.isNotNull, null) {
|
||||
@Override
|
||||
protected void populateOperator(StringBuilder sb) {
|
||||
sb.append(SPACE).append(operator);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Criterion like(Field field, String value) {
|
||||
return new UnaryCriterion(field, Operator.like, value) {
|
||||
@Override
|
||||
protected void populateOperator(StringBuilder sb) {
|
||||
sb.append(SPACE).append(operator).append(SPACE);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Represents an add-onn for Astrid. Users can enable or disable add-ons,
|
||||
* which affect all other extension points that share the same identifier.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class Addon implements Parcelable {
|
||||
|
||||
/**
|
||||
* Add-on Identifier
|
||||
*/
|
||||
public String addon = null;
|
||||
|
||||
/**
|
||||
* Plug-in Title
|
||||
*/
|
||||
public String title = null;
|
||||
|
||||
/**
|
||||
* Plug-in Author
|
||||
*/
|
||||
public String author = null;
|
||||
|
||||
/**
|
||||
* Plug-in Description
|
||||
*/
|
||||
public String description = null;
|
||||
|
||||
/**
|
||||
* Convenience constructor to generate a plug-in object
|
||||
*
|
||||
* @param addon
|
||||
* @param title
|
||||
* @param author
|
||||
* @param description
|
||||
*/
|
||||
public Addon(String addon, String title, String author, String description) {
|
||||
this.addon = addon;
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
// --- parcelable helpers
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(addon);
|
||||
dest.writeString(title);
|
||||
dest.writeString(author);
|
||||
dest.writeString(description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcelable creator
|
||||
*/
|
||||
public static final Parcelable.Creator<Addon> CREATOR = new Parcelable.Creator<Addon>() {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Addon createFromParcel(Parcel source) {
|
||||
return new Addon(source.readString(), source.readString(),
|
||||
source.readString(), source.readString());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Addon[] newArray(int size) {
|
||||
return new Addon[size];
|
||||
};
|
||||
};
|
||||
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
/**
|
||||
* Constants for interfacing with Astrid.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class AstridApiConstants {
|
||||
|
||||
// --- General Constants
|
||||
|
||||
/**
|
||||
* Astrid application package name
|
||||
*/
|
||||
public static final String PACKAGE = "com.todoroo.astrid";
|
||||
|
||||
/**
|
||||
* Permission for reading tasks and receiving to GET_FILTERS intent
|
||||
*/
|
||||
public static final String PERMISSION_READ = PACKAGE + ".READ";
|
||||
|
||||
/**
|
||||
* Permission for writing and creating tasks
|
||||
*/
|
||||
public static final String PERMISSION_WRITE = PACKAGE + ".WRITE";
|
||||
|
||||
// --- Broadcast Extras
|
||||
|
||||
/**
|
||||
* Extras name for task id
|
||||
*/
|
||||
public static final String EXTRAS_TASK_ID = "task";
|
||||
|
||||
/**
|
||||
* Extras name for a response item broadcast to astrid
|
||||
*/
|
||||
public static final String EXTRAS_RESPONSE = "response";
|
||||
|
||||
/**
|
||||
* Extras name for plug-in identifier
|
||||
*/
|
||||
public static final String EXTRAS_ADDON = "addon";
|
||||
|
||||
/**
|
||||
* Extras name for whether task detail request is extended
|
||||
*/
|
||||
public static final String EXTRAS_EXTENDED = "extended";
|
||||
|
||||
// --- Add-ons API
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent requesting add-ons
|
||||
*/
|
||||
public static final String BROADCAST_REQUEST_ADDONS = PACKAGE + ".REQUEST_ADDONS";
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent sending add-ons back to Astrid
|
||||
* @extra EXTRAS_RESPONSE an {@link Addon} object
|
||||
*/
|
||||
public static final String BROADCAST_SEND_ADDONS = PACKAGE + ".SEND_ADDONS";
|
||||
|
||||
// --- Filters API
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent requesting filters
|
||||
*/
|
||||
public static final String BROADCAST_REQUEST_FILTERS = PACKAGE + ".REQUEST_FILTERS";
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent sending filters back to Astrid
|
||||
* @extra EXTRAS_ADDON your add-on identifier
|
||||
* @extra EXTRAS_RESPONSE an array of {@link FilterListItem}s
|
||||
*/
|
||||
public static final String BROADCAST_SEND_FILTERS = PACKAGE + ".SEND_FILTERS";
|
||||
|
||||
// --- Edit Controls API
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent requesting task edit controls
|
||||
* @extra EXTRAS_TASK_ID id of the task user is editing
|
||||
*/
|
||||
public static final String BROADCAST_REQUEST_EDIT_CONTROLS = PACKAGE + ".REQUEST_EDIT_CONTROLS";
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent sending task edit controls back to Astrid
|
||||
* @extra EXTRAS_ADDON your add-on identifier
|
||||
* @extra EXTRAS_RESPONSE a {@link RemoteViews} with your edit controls
|
||||
*/
|
||||
public static final String BROADCAST_SEND_EDIT_CONTROLS = PACKAGE + ".SEND_EDIT_CONTROLS";
|
||||
|
||||
// --- Task Details API
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent requesting details for a task.
|
||||
* Extended details are displayed when a user presses on a task.
|
||||
*
|
||||
* @extra EXTRAS_TASK_ID id of the task
|
||||
* @extra EXTRAS_EXTENDED whether request is for standard or extended details
|
||||
*/
|
||||
public static final String BROADCAST_REQUEST_DETAILS = PACKAGE + ".REQUEST_DETAILS";
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent sending details back to Astrid
|
||||
* @extra EXTRAS_ADDON your add-on identifier
|
||||
* @extra EXTRAS_TASK_ID id of the task
|
||||
* @extra EXTRAS_EXTENDED whether request is for standard or extended details
|
||||
* @extra EXTRAS_RESPONSE a String
|
||||
*/
|
||||
public static final String BROADCAST_SEND_DETAILS = PACKAGE + ".SEND_DETAILS";
|
||||
|
||||
// --- Task Actions API
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent requesting actions for a task
|
||||
* @extra EXTRAS_TASK_ID id of the task
|
||||
*/
|
||||
public static final String BROADCAST_REQUEST_ACTIONS = PACKAGE + ".REQUEST_ACTIONS";
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent sending actions back to Astrid
|
||||
* @extra EXTRAS_ADDON your add-on identifier
|
||||
* @extra EXTRAS_TASK_ID id of the task
|
||||
* @extra EXTRAS_RESPONSE a String
|
||||
*/
|
||||
public static final String BROADCAST_SEND_ACTIONS = PACKAGE + ".SEND_ACTIONS";
|
||||
|
||||
// --- Task Decorations API
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent requesting task list decorations for a task
|
||||
* @extra EXTRAS_TASK_ID id of the task
|
||||
*/
|
||||
public static final String BROADCAST_REQUEST_DECORATIONS = PACKAGE + ".REQUEST_DECORATIONS";
|
||||
|
||||
// --- Actions API
|
||||
|
||||
/**
|
||||
* Action name for intents to be displayed on task context menu
|
||||
* @extra EXTRAS_TASK_ID id of the task
|
||||
*/
|
||||
public static final String ACTION_TASK_CONTEXT_MENU = PACKAGE + ".CONTEXT_MENU";
|
||||
|
||||
/**
|
||||
* Action name for intents to be displayed on Astrid's task list menu
|
||||
* @extra EXTRAS_ADDON your add-on identifier
|
||||
* @extra EXTRAS_RESPONSE an array of {@link Intent}s
|
||||
*/
|
||||
public static final String ACTION_TASK_LIST_MENU = PACKAGE + ".TASK_LIST_MENU";
|
||||
|
||||
// --- Settings API
|
||||
|
||||
/**
|
||||
* Action name for intents to be displayed in Astrid's settings
|
||||
*/
|
||||
public static final String ACTION_SETTINGS = PACKAGE + ".SETTINGS";
|
||||
|
||||
// --- Events API
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent notifying that task was completed
|
||||
* @extra EXTRAS_TASK_ID id of the task
|
||||
*/
|
||||
public static final String BROADCAST_EVENT_TASK_COMPLETED = PACKAGE + ".TASK_COMPLETED";
|
||||
|
||||
/**
|
||||
* Action name for broadcast intent notifying that task was created
|
||||
* @extra EXTRAS_TASK_ID id of the task
|
||||
*/
|
||||
public static final String BROADCAST_EVENT_TASK_CREATED = PACKAGE + ".TASK_CREATED";
|
||||
|
||||
// --- SQL Constants
|
||||
|
||||
/**
|
||||
* Table name for tasks
|
||||
*/
|
||||
public static final String TASK_TABLE = "tasks";
|
||||
|
||||
/**
|
||||
* Table name for metadata
|
||||
*/
|
||||
public static final String METADATA_TABLE = "metadata";
|
||||
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.todoroo.andlib.QueryTemplate;
|
||||
|
||||
/**
|
||||
* A <code>FilterListFilter</code> allows users to display tasks that have
|
||||
* something in common.
|
||||
* <p>
|
||||
* A plug-in can expose new <code>FilterListFilter</code>s to the system by
|
||||
* responding to the <code>com.todoroo.astrid.GET_FILTERS</code> broadcast
|
||||
* intent.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public final class Filter extends FilterListItem {
|
||||
|
||||
// --- constants
|
||||
|
||||
/** Constant for valuesForNewTasks to indicate the value should be replaced
|
||||
* with the current time as long */
|
||||
public static final long VALUE_NOW = Long.MIN_VALUE + 1;
|
||||
|
||||
// --- instance variables
|
||||
|
||||
/**
|
||||
* Expanded title of this filter. This is displayed at the top
|
||||
* of the screen when user is viewing this filter.
|
||||
* <p>
|
||||
* e.g "Tasks With Notes"
|
||||
*/
|
||||
public String title;
|
||||
|
||||
/**
|
||||
* SQL query for this filter. The query will be appended to the select
|
||||
* statement after "<code>SELECT fields FROM table %s</code>". It is
|
||||
* recommended that you use a {@link QueryTemplate} to construct your
|
||||
* query.
|
||||
* <p>
|
||||
* Examples:
|
||||
* <ul>
|
||||
* <li><code>"WHERE completionDate = 0"</code>
|
||||
* <li><code>"INNER JOIN " +
|
||||
* Constants.TABLE_METADATA + " ON metadata.task = tasks.id WHERE
|
||||
* metadata.namespace = " + NAMESPACE + " AND metadata.key = 'a' AND
|
||||
* metadata.value = 'b' GROUP BY tasks.id ORDER BY tasks.title"</code>
|
||||
* </ul>
|
||||
*/
|
||||
public String sqlQuery;
|
||||
|
||||
/**
|
||||
* Values to apply to a task when quick-adding a task from this filter.
|
||||
* For example, when a user views tasks tagged 'ABC', the
|
||||
* tasks they create should also be tagged 'ABC'. If set to null, no
|
||||
* additional values will be stored for a task.
|
||||
*/
|
||||
public ContentValues valuesForNewTasks = null;
|
||||
|
||||
/**
|
||||
* Utility constructor for creating a TaskList object
|
||||
* @param listingTitle
|
||||
* Title of this item as displayed on the lists page, e.g. Inbox
|
||||
* @param title
|
||||
* Expanded title of this filter when user is viewing this
|
||||
* filter, e.g. Inbox (20 tasks)
|
||||
* @param sqlQuery
|
||||
* SQL query for this list (see {@link sqlQuery} for examples).
|
||||
* @param valuesForNewTasks
|
||||
* see {@link sqlForNewTasks}
|
||||
*/
|
||||
public Filter(String listingTitle, String title,
|
||||
QueryTemplate sqlQuery, ContentValues valuesForNewTasks) {
|
||||
this.listingTitle = listingTitle;
|
||||
this.title = title;
|
||||
if(sqlQuery != null)
|
||||
this.sqlQuery = sqlQuery.toString();
|
||||
this.valuesForNewTasks = valuesForNewTasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility constructor
|
||||
*
|
||||
* @param plugin
|
||||
* {@link Addon} identifier that encompasses object
|
||||
*/
|
||||
protected Filter() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// --- parcelable
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeString(title);
|
||||
dest.writeString(sqlQuery);
|
||||
dest.writeParcelable(valuesForNewTasks, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcelable Creator Object
|
||||
*/
|
||||
public static final Parcelable.Creator<Filter> CREATOR = new Parcelable.Creator<Filter>() {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Filter createFromParcel(Parcel source) {
|
||||
Filter item = new Filter();
|
||||
item.readFromParcel(source);
|
||||
item.title = source.readString();
|
||||
item.sqlQuery = source.readString();
|
||||
item.valuesForNewTasks = source.readParcelable(ContentValues.class.getClassLoader());
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Filter[] newArray(int size) {
|
||||
return new Filter[size];
|
||||
}
|
||||
|
||||
};
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* A <code>FilterCategory</code> groups common {@link Filter}s and allows
|
||||
* a user to show/hide all of its children.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class FilterCategory extends FilterListItem {
|
||||
|
||||
/**
|
||||
* {@link Filter}s contained by this category
|
||||
*/
|
||||
public Filter[] children;
|
||||
|
||||
/**
|
||||
* Constructor for creating a new FilterCategory
|
||||
* @param listingTitle
|
||||
* Title of this item as displayed on the lists page, e.g. Inbox
|
||||
* @param children
|
||||
* filters belonging to this category
|
||||
*/
|
||||
public FilterCategory(String listingTitle, Filter[] children) {
|
||||
this.listingTitle = listingTitle;
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for creating a new FilterCategory
|
||||
*
|
||||
* @param plugin
|
||||
* {@link Addon} identifier that encompasses object
|
||||
*/
|
||||
protected FilterCategory() {
|
||||
//
|
||||
}
|
||||
|
||||
// --- parcelable
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeParcelableArray(children, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcelable creator
|
||||
*/
|
||||
public static final Parcelable.Creator<FilterCategory> CREATOR = new Parcelable.Creator<FilterCategory>() {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public FilterCategory createFromParcel(Parcel source) {
|
||||
FilterCategory item = new FilterCategory();
|
||||
item.readFromParcel(source);
|
||||
|
||||
Parcelable[] parcelableChildren = source.readParcelableArray(
|
||||
FilterCategory.class.getClassLoader());
|
||||
item.children = new Filter[parcelableChildren.length];
|
||||
for(int i = 0; i < item.children.length; i++) {
|
||||
if(parcelableChildren[i] instanceof FilterListItem)
|
||||
item.children[i] = (Filter) parcelableChildren[i];
|
||||
else
|
||||
item.children[i] = null;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public FilterCategory[] newArray(int size) {
|
||||
return new FilterCategory[size];
|
||||
}
|
||||
|
||||
};
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Section Header for Filter List
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class FilterListHeader extends FilterListItem {
|
||||
|
||||
/**
|
||||
* Constructor for creating a new FilterListHeader
|
||||
* @param listingTitle
|
||||
* @param listingIconResource
|
||||
* @param priority
|
||||
*/
|
||||
public FilterListHeader(String listingTitle) {
|
||||
this.listingTitle = listingTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for creating a new FilterListHeader
|
||||
*
|
||||
* @param plugin
|
||||
* {@link Addon} identifier that encompasses object
|
||||
*/
|
||||
protected FilterListHeader() {
|
||||
//
|
||||
}
|
||||
|
||||
// --- parcelable
|
||||
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<FilterListHeader> CREATOR = new Parcelable.Creator<FilterListHeader>() {
|
||||
|
||||
public FilterListHeader createFromParcel(Parcel source) {
|
||||
FilterListHeader item = new FilterListHeader();
|
||||
item.readFromParcel(source);
|
||||
return item;
|
||||
}
|
||||
|
||||
public FilterListHeader[] newArray(int size) {
|
||||
return new FilterListHeader[size];
|
||||
}
|
||||
|
||||
};
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Represents an item displayed by Astrid's FilterListActivity
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
abstract public class FilterListItem implements Parcelable {
|
||||
|
||||
/**
|
||||
* Title of this item displayed on the Filters page
|
||||
*/
|
||||
public String listingTitle = null;
|
||||
|
||||
/**
|
||||
* Bitmap for icon used on listing page. <code>null</code> => no icon
|
||||
*/
|
||||
public Bitmap listingIcon = null;
|
||||
|
||||
/**
|
||||
* Context Menu labels. The context menu will be displayed when users
|
||||
* long-press on this filter list item.
|
||||
*/
|
||||
public String contextMenuLabels[] = new String[0];
|
||||
|
||||
/**
|
||||
* Context menu intents. This intent will be started when the corresponding
|
||||
* content menu label is invoked. This array must be the same size as
|
||||
* the contextMenuLabels array.
|
||||
*/
|
||||
public Intent contextMenuIntents[] = new Intent[0];
|
||||
|
||||
// --- parcelable helpers
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(listingTitle);
|
||||
dest.writeParcelable(listingIcon, 0);
|
||||
|
||||
// write array lengths before arrays
|
||||
dest.writeInt(contextMenuLabels.length);
|
||||
dest.writeStringArray(contextMenuLabels);
|
||||
dest.writeInt(contextMenuIntents.length);
|
||||
dest.writeTypedArray(contextMenuIntents, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to read FilterListItem properties from a parcel.
|
||||
*
|
||||
* @param source
|
||||
*/
|
||||
public void readFromParcel(Parcel source) {
|
||||
listingTitle = source.readString();
|
||||
listingIcon = source.readParcelable(Bitmap.class.getClassLoader());
|
||||
|
||||
int length = source.readInt();
|
||||
contextMenuLabels = new String[length];
|
||||
source.readStringArray(contextMenuLabels);
|
||||
length = source.readInt();
|
||||
contextMenuIntents = new Intent[length];
|
||||
source.readTypedArray(contextMenuIntents, Intent.CREATOR);
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Represents an intent that can be called on a task
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class TaskAction implements Parcelable {
|
||||
|
||||
/**
|
||||
* Label
|
||||
*/
|
||||
public String text = null;
|
||||
|
||||
/**
|
||||
* Intent to call when invoking this operation
|
||||
*/
|
||||
public PendingIntent intent = null;
|
||||
|
||||
/**
|
||||
* Create an EditOperation object
|
||||
*
|
||||
* @param text
|
||||
* label to display
|
||||
* @param intent
|
||||
* intent to invoke. {@link EXTRAS_TASK_ID} will be passed
|
||||
*/
|
||||
public TaskAction(String text, PendingIntent intent) {
|
||||
super();
|
||||
this.text = text;
|
||||
this.intent = intent;
|
||||
}
|
||||
|
||||
// --- parcelable helpers
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(text);
|
||||
dest.writeParcelable(intent, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcelable creator
|
||||
*/
|
||||
public static final Parcelable.Creator<TaskAction> CREATOR = new Parcelable.Creator<TaskAction>() {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public TaskAction createFromParcel(Parcel source) {
|
||||
return new TaskAction(source.readString(), (PendingIntent)source.readParcelable(
|
||||
PendingIntent.class.getClassLoader()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public TaskAction[] newArray(int size) {
|
||||
return new TaskAction[size];
|
||||
};
|
||||
};
|
||||
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.api;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.RemoteViews.RemoteView;
|
||||
|
||||
/**
|
||||
* Represents a line of text displayed in the Task List
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public final class TaskDecoration implements Parcelable {
|
||||
|
||||
/**
|
||||
* Place decoration between completion box and task title
|
||||
*/
|
||||
public static final int POSITION_LEFT = 0;
|
||||
|
||||
/**
|
||||
* Place decoration between task title and importance bar
|
||||
*/
|
||||
public static final int POSITION_RIGHT = 1;
|
||||
|
||||
/**
|
||||
* {@link RemoteView} decoration
|
||||
*/
|
||||
public RemoteViews decoration = null;
|
||||
|
||||
/**
|
||||
* Decoration position
|
||||
*/
|
||||
public int position = POSITION_LEFT;
|
||||
|
||||
/**
|
||||
* Decorated task background color. 0 is default
|
||||
*/
|
||||
public int color = 0;
|
||||
|
||||
/**
|
||||
* Creates a TaskDetail object
|
||||
* @param text
|
||||
* text to display
|
||||
* @param color
|
||||
* color to use for text. Use <code>0</code> for default color
|
||||
*/
|
||||
public TaskDecoration(RemoteViews decoration, int position, int color) {
|
||||
this.decoration = decoration;
|
||||
this.position = position;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
// --- parcelable helpers
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(decoration, 0);
|
||||
dest.writeInt(position);
|
||||
dest.writeInt(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcelable creator
|
||||
*/
|
||||
public static final Parcelable.Creator<TaskDecoration> CREATOR = new Parcelable.Creator<TaskDecoration>() {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public TaskDecoration createFromParcel(Parcel source) {
|
||||
return new TaskDecoration((RemoteViews)source.readParcelable(
|
||||
RemoteViews.class.getClassLoader()),
|
||||
source.readInt(), source.readInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public TaskDecoration[] newArray(int size) {
|
||||
return new TaskDecoration[size];
|
||||
};
|
||||
};
|
||||
|
||||
}
|
@ -1,425 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.data;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.todoroo.astrid.data.Property.DoubleProperty;
|
||||
import com.todoroo.astrid.data.Property.IntegerProperty;
|
||||
import com.todoroo.astrid.data.Property.LongProperty;
|
||||
import com.todoroo.astrid.data.Property.PropertyVisitor;
|
||||
|
||||
/**
|
||||
* <code>AbstractModel</code> represents a row in a database.
|
||||
* <p>
|
||||
* A single database can be represented by multiple <code>AbstractModel</code>s
|
||||
* corresponding to different queries that return a different set of columns.
|
||||
* Each model exposes a set of properties that it contains.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractModel implements Parcelable {
|
||||
|
||||
// --- static variables
|
||||
|
||||
private static final ContentValuesSavingVisitor saver = new ContentValuesSavingVisitor();
|
||||
|
||||
// --- constants
|
||||
|
||||
/** id property common to all models */
|
||||
protected static final String ID_PROPERTY_NAME = "_id"; //$NON-NLS-1$
|
||||
|
||||
/** id field common to all models */
|
||||
public static final IntegerProperty ID_PROPERTY = new IntegerProperty(null, ID_PROPERTY_NAME);
|
||||
|
||||
/** sentinel for objects without an id */
|
||||
public static final long NO_ID = 0;
|
||||
|
||||
// --- abstract methods
|
||||
|
||||
/** Get the default values for this object */
|
||||
abstract public ContentValues getDefaultValues();
|
||||
|
||||
// --- data store variables and management
|
||||
|
||||
/* Data Source Ordering:
|
||||
*
|
||||
* In order to return the best data, we want to check first what the user
|
||||
* has explicitly set (setValues), then the values we have read out of
|
||||
* the database (values), then defaults (getDefaultValues)
|
||||
*/
|
||||
|
||||
/** User set values */
|
||||
protected ContentValues setValues = null;
|
||||
|
||||
/** Values from database */
|
||||
protected ContentValues values = null;
|
||||
|
||||
/** Get database-read values for this object */
|
||||
public ContentValues getDatabaseValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
/** Get the user-set values for this object */
|
||||
public ContentValues getSetValues() {
|
||||
return setValues;
|
||||
}
|
||||
|
||||
/** Get a list of all field/value pairs merged across data sources */
|
||||
public ContentValues getMergedValues() {
|
||||
ContentValues mergedValues = new ContentValues();
|
||||
|
||||
ContentValues defaultValues = getDefaultValues();
|
||||
if(defaultValues != null)
|
||||
mergedValues.putAll(defaultValues);
|
||||
if(values != null)
|
||||
mergedValues.putAll(values);
|
||||
if(setValues != null)
|
||||
mergedValues.putAll(setValues);
|
||||
|
||||
return mergedValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all data on this model
|
||||
*/
|
||||
public void clear() {
|
||||
values = null;
|
||||
setValues = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfers all set values into values. This occurs when a task is
|
||||
* saved - future saves will not need to write all the data as before.
|
||||
*/
|
||||
public void markSaved() {
|
||||
if(values == null)
|
||||
values = setValues;
|
||||
else if(setValues != null)
|
||||
values.putAll(setValues);
|
||||
setValues = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use merged values to compare two models to each other. Must be of
|
||||
* exactly the same class.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if(other == null || other.getClass() != getClass())
|
||||
return false;
|
||||
|
||||
return getMergedValues().equals(((AbstractModel)other).getMergedValues());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getMergedValues().hashCode() ^ getClass().hashCode();
|
||||
}
|
||||
|
||||
// --- data retrieval
|
||||
|
||||
/**
|
||||
* Reads all properties from the supplied cursor and store
|
||||
*/
|
||||
protected synchronized void readPropertiesFromCursor(TodorooCursor<? extends AbstractModel> cursor) {
|
||||
if (values == null)
|
||||
values = new ContentValues();
|
||||
|
||||
// clears user-set values
|
||||
setValues = null;
|
||||
|
||||
for (Property<?> property : cursor.getProperties()) {
|
||||
saver.save(property, values, cursor.get(property));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the given property. Make sure this model has this property!
|
||||
*/
|
||||
public synchronized <TYPE> TYPE getValue(Property<TYPE> property) {
|
||||
Object value;
|
||||
if(setValues != null && setValues.containsKey(property.name))
|
||||
value = setValues.get(property.name);
|
||||
|
||||
else if(values != null && values.containsKey(property.name) && (values.get(property.name) != null))
|
||||
value = values.get(property.name);
|
||||
|
||||
else if(getDefaultValues().containsKey(property.name))
|
||||
value = getDefaultValues().get(property.name);
|
||||
|
||||
else
|
||||
throw new UnsupportedOperationException(
|
||||
"Model Error: Did not read property " + property.name); //$NON-NLS-1$
|
||||
|
||||
// resolve properties that were retrieved with a different type than accessed
|
||||
if(value instanceof String && property instanceof LongProperty)
|
||||
return (TYPE) Long.valueOf((String)value);
|
||||
else if(value instanceof String && property instanceof IntegerProperty)
|
||||
return (TYPE) Integer.valueOf((String)value);
|
||||
if(value instanceof String && property instanceof DoubleProperty)
|
||||
return (TYPE) Double.valueOf((String)value);
|
||||
return (TYPE) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to get the identifier of the model, if it exists.
|
||||
*
|
||||
* @return {@value #NO_ID} if this model was not added to the database
|
||||
*/
|
||||
abstract public long getId();
|
||||
|
||||
protected long getIdHelper(LongProperty id) {
|
||||
if(setValues != null && setValues.containsKey(id.name))
|
||||
return setValues.getAsLong(id.name);
|
||||
else if(values != null && values.containsKey(id.name))
|
||||
return values.getAsLong(id.name);
|
||||
else
|
||||
return NO_ID;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
if (setValues == null)
|
||||
setValues = new ContentValues();
|
||||
|
||||
if(id == NO_ID)
|
||||
setValues.remove(ID_PROPERTY_NAME);
|
||||
else
|
||||
setValues.put(ID_PROPERTY_NAME, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this model has found Jesus (i.e. the database)
|
||||
*/
|
||||
public boolean isSaved() {
|
||||
return getId() != NO_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param property
|
||||
* @return true if setValues or values contains this property
|
||||
*/
|
||||
public boolean containsValue(Property<?> property) {
|
||||
if(setValues != null && setValues.containsKey(property.name))
|
||||
return true;
|
||||
if(values != null && values.containsKey(property.name))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param property
|
||||
* @return true if setValues or values contains this property, and the value
|
||||
* stored is not null
|
||||
*/
|
||||
public boolean containsNonNullValue(Property<?> property) {
|
||||
if(setValues != null && setValues.containsKey(property.name))
|
||||
return setValues.get(property.name) != null;
|
||||
if(values != null && values.containsKey(property.name))
|
||||
return values.get(property.name) != null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- data storage
|
||||
|
||||
/**
|
||||
* Check whether the user has changed this property value and it should be
|
||||
* stored for saving in the database
|
||||
*/
|
||||
protected synchronized <TYPE> boolean shouldSaveValue(
|
||||
Property<TYPE> property, TYPE newValue) {
|
||||
|
||||
// we've already decided to save it, so overwrite old value
|
||||
if (setValues.containsKey(property.name))
|
||||
return true;
|
||||
|
||||
// values contains this key, we should check it out
|
||||
if(values != null && values.containsKey(property.name)) {
|
||||
TYPE value = getValue(property);
|
||||
if (value == null) {
|
||||
if (newValue == null)
|
||||
return false;
|
||||
} else if (value.equals(newValue))
|
||||
return false;
|
||||
}
|
||||
|
||||
// otherwise, good to save
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given property. Make sure this model has this property!
|
||||
*/
|
||||
public synchronized <TYPE> void setValue(Property<TYPE> property,
|
||||
TYPE value) {
|
||||
if (setValues == null)
|
||||
setValues = new ContentValues();
|
||||
if (!shouldSaveValue(property, value))
|
||||
return;
|
||||
|
||||
saver.save(property, setValues, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges content values with those coming from another source
|
||||
*/
|
||||
public synchronized <TYPE> void mergeWith(ContentValues other) {
|
||||
if (setValues == null)
|
||||
setValues = other;
|
||||
else
|
||||
setValues.putAll(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the key for the given property
|
||||
* @param property
|
||||
*/
|
||||
public synchronized void clearValue(Property<?> property) {
|
||||
if(setValues != null && setValues.containsKey(property.name))
|
||||
setValues.remove(property.name);
|
||||
else if(values != null && values.containsKey(property.name))
|
||||
values.remove(property.name);
|
||||
else if(getDefaultValues().containsKey(property.name))
|
||||
throw new IllegalArgumentException("Property has a default value"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
// --- property management
|
||||
|
||||
/**
|
||||
* Looks inside the given class and finds all declared properties
|
||||
*/
|
||||
protected static Property<?>[] generateProperties(Class<? extends AbstractModel> cls) {
|
||||
ArrayList<Property<?>> properties = new ArrayList<Property<?>>();
|
||||
if(cls.getSuperclass() != AbstractModel.class)
|
||||
properties.addAll(Arrays.asList(generateProperties(
|
||||
(Class<? extends AbstractModel>) cls.getSuperclass())));
|
||||
|
||||
// a property is public, static & extends Property
|
||||
for(Field field : cls.getFields()) {
|
||||
if((field.getModifiers() & Modifier.STATIC) == 0)
|
||||
continue;
|
||||
if(!Property.class.isAssignableFrom(field.getType()))
|
||||
continue;
|
||||
try {
|
||||
properties.add((Property<?>) field.get(null));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return properties.toArray(new Property<?>[properties.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visitor that saves a value into a content values store
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public static class ContentValuesSavingVisitor implements PropertyVisitor<Void, Object> {
|
||||
|
||||
private ContentValues store;
|
||||
|
||||
public synchronized void save(Property<?> property, ContentValues newStore, Object value) {
|
||||
this.store = newStore;
|
||||
property.accept(this, value);
|
||||
}
|
||||
|
||||
public Void visitDouble(Property<Double> property, Object value) {
|
||||
store.put(property.name, (Double) value);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Void visitInteger(Property<Integer> property, Object value) {
|
||||
store.put(property.name, (Integer) value);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Void visitLong(Property<Long> property, Object value) {
|
||||
store.put(property.name, (Long) value);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Void visitString(Property<String> property, Object value) {
|
||||
store.put(property.name, (String) value);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// --- parcelable helpers
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(setValues, 0);
|
||||
dest.writeParcelable(values, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* In addition to overriding this class, model classes should create
|
||||
* a static final variable named "CREATOR" in order to satisfy the
|
||||
* requirements of the Parcelable interface.
|
||||
*/
|
||||
abstract protected Parcelable.Creator<? extends AbstractModel> getCreator();
|
||||
|
||||
/**
|
||||
* Parcelable creator helper
|
||||
*/
|
||||
protected static final class ModelCreator<TYPE extends AbstractModel>
|
||||
implements Parcelable.Creator<TYPE> {
|
||||
|
||||
private final Class<TYPE> cls;
|
||||
|
||||
public ModelCreator(Class<TYPE> cls) {
|
||||
super();
|
||||
this.cls = cls;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public TYPE createFromParcel(Parcel source) {
|
||||
TYPE model;
|
||||
try {
|
||||
model = cls.newInstance();
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
model.setValues = source.readParcelable(ContentValues.class.getClassLoader());
|
||||
model.values = source.readParcelable(ContentValues.class.getClassLoader());
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public TYPE[] newArray(int size) {
|
||||
return (TYPE[]) Array.newInstance(cls, size);
|
||||
};
|
||||
};
|
||||
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.data;
|
||||
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import com.todoroo.astrid.data.Property.LongProperty;
|
||||
import com.todoroo.astrid.data.Property.StringProperty;
|
||||
|
||||
/**
|
||||
* Data Model which represents a piece of metadata associated with a task
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class Metadata extends AbstractModel {
|
||||
|
||||
// --- table
|
||||
|
||||
public static final Table TABLE = new Table("metadata", Metadata.class);
|
||||
|
||||
// --- properties
|
||||
|
||||
/** ID */
|
||||
public static final LongProperty ID = new LongProperty(
|
||||
TABLE, ID_PROPERTY_NAME);
|
||||
|
||||
/** Associated Task */
|
||||
public static final LongProperty TASK = new LongProperty(
|
||||
TABLE, "task");
|
||||
|
||||
/** Metadata Key */
|
||||
public static final StringProperty KEY = new StringProperty(
|
||||
TABLE, "key");
|
||||
|
||||
/** Metadata Text Value Column 1 */
|
||||
public static final StringProperty VALUE1 = new StringProperty(
|
||||
TABLE, "value");
|
||||
|
||||
/** Metadata Text Value Column 2 */
|
||||
public static final StringProperty VALUE2 = new StringProperty(
|
||||
TABLE, "value2");
|
||||
|
||||
/** Metadata Text Value Column 1 */
|
||||
public static final StringProperty VALUE3 = new StringProperty(
|
||||
TABLE, "value3");
|
||||
|
||||
/** Metadata Text Value Column 1 */
|
||||
public static final StringProperty VALUE4 = new StringProperty(
|
||||
TABLE, "value4");
|
||||
|
||||
/** Metadata Text Value Column 1 */
|
||||
public static final StringProperty VALUE5 = new StringProperty(
|
||||
TABLE, "value5");
|
||||
|
||||
/** List of all properties for this model */
|
||||
public static final Property<?>[] PROPERTIES = generateProperties(Metadata.class);
|
||||
|
||||
// --- defaults
|
||||
|
||||
/** Default values container */
|
||||
private static final ContentValues defaultValues = new ContentValues();
|
||||
|
||||
@Override
|
||||
public ContentValues getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
// --- data access boilerplate
|
||||
|
||||
public Metadata() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Metadata(TodorooCursor<Metadata> cursor) {
|
||||
this();
|
||||
readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
public void readFromCursor(TodorooCursor<Metadata> cursor) {
|
||||
super.readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return getIdHelper(ID);
|
||||
};
|
||||
|
||||
// --- parcelable helpers
|
||||
|
||||
private static final Creator<Task> CREATOR = new ModelCreator<Task>(Task.class);
|
||||
|
||||
@Override
|
||||
protected Creator<? extends AbstractModel> getCreator() {
|
||||
return CREATOR;
|
||||
}
|
||||
|
||||
}
|
@ -1,208 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.data;
|
||||
|
||||
import com.todoroo.andlib.Field;
|
||||
|
||||
/**
|
||||
* Property represents a typed column in a database.
|
||||
*
|
||||
* Within a given database row, the parameter may not exist, in which case the
|
||||
* value is null, it may be of an incorrect type, in which case an exception is
|
||||
* thrown, or the correct type, in which case the value is returned.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
* @param <TYPE>
|
||||
* a database supported type, such as String or Integer
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public abstract class Property<TYPE> extends Field implements Cloneable {
|
||||
|
||||
// --- implementation
|
||||
|
||||
/** The database table name this property */
|
||||
public final Table table;
|
||||
|
||||
/** The database column name for this property */
|
||||
public final String name;
|
||||
|
||||
/**
|
||||
* Create a property by table and column name. Uses the default property
|
||||
* expression which is derived from default table name
|
||||
*/
|
||||
protected Property(Table table, String columnName) {
|
||||
this(table, columnName, (table == null) ? (columnName) : (table.name + "." + columnName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a property by table and column name, manually specifying an
|
||||
* expression to use in SQL
|
||||
*/
|
||||
protected Property(Table table, String columnName, String expression) {
|
||||
super(expression);
|
||||
this.table = table;
|
||||
this.name = columnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept a visitor
|
||||
*/
|
||||
abstract public <RETURN, PARAMETER> RETURN accept(
|
||||
PropertyVisitor<RETURN, PARAMETER> visitor, PARAMETER data);
|
||||
|
||||
/**
|
||||
* Return a clone of this property
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Property<TYPE> clone() {
|
||||
try {
|
||||
return (Property<TYPE>) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// --- helper classes and interfaces
|
||||
|
||||
/**
|
||||
* Visitor interface for property classes
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public interface PropertyVisitor<RETURN, PARAMETER> {
|
||||
public RETURN visitInteger(Property<Integer> property, PARAMETER data);
|
||||
|
||||
public RETURN visitLong(Property<Long> property, PARAMETER data);
|
||||
|
||||
public RETURN visitDouble(Property<Double> property, PARAMETER data);
|
||||
|
||||
public RETURN visitString(Property<String> property, PARAMETER data);
|
||||
}
|
||||
|
||||
// --- children
|
||||
|
||||
/**
|
||||
* Integer property type. See {@link Property}
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public static class IntegerProperty extends Property<Integer> {
|
||||
|
||||
public IntegerProperty(Table table, String name) {
|
||||
super(table, name);
|
||||
}
|
||||
|
||||
protected IntegerProperty(Table table, String name, String expression) {
|
||||
super(table, name, expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <RETURN, PARAMETER> RETURN accept(
|
||||
PropertyVisitor<RETURN, PARAMETER> visitor, PARAMETER data) {
|
||||
return visitor.visitInteger(this, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* String property type. See {@link Property}
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public static class StringProperty extends Property<String> {
|
||||
|
||||
public StringProperty(Table table, String name) {
|
||||
super(table, name);
|
||||
}
|
||||
|
||||
protected StringProperty(Table table, String name, String expression) {
|
||||
super(table, name, expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <RETURN, PARAMETER> RETURN accept(
|
||||
PropertyVisitor<RETURN, PARAMETER> visitor, PARAMETER data) {
|
||||
return visitor.visitString(this, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Double property type. See {@link Property}
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public static class DoubleProperty extends Property<Double> {
|
||||
|
||||
public DoubleProperty(Table table, String name) {
|
||||
super(table, name);
|
||||
}
|
||||
|
||||
protected DoubleProperty(Table table, String name, String expression) {
|
||||
super(table, name, expression);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <RETURN, PARAMETER> RETURN accept(
|
||||
PropertyVisitor<RETURN, PARAMETER> visitor, PARAMETER data) {
|
||||
return visitor.visitDouble(this, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Long property type. See {@link Property}
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public static class LongProperty extends Property<Long> {
|
||||
|
||||
public LongProperty(Table table, String name) {
|
||||
super(table, name);
|
||||
}
|
||||
|
||||
protected LongProperty(Table table, String name, String expression) {
|
||||
super(table, name, expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <RETURN, PARAMETER> RETURN accept(
|
||||
PropertyVisitor<RETURN, PARAMETER> visitor, PARAMETER data) {
|
||||
return visitor.visitLong(this, data);
|
||||
}
|
||||
}
|
||||
|
||||
// --- pseudo-properties
|
||||
|
||||
/** Runs a SQL function and returns the result as a string */
|
||||
public static class StringFunctionProperty extends StringProperty {
|
||||
public StringFunctionProperty(String function, String columnName) {
|
||||
super(null, columnName, function);
|
||||
alias = columnName;
|
||||
}
|
||||
}
|
||||
|
||||
/** Runs a SQL function and returns the result as a string */
|
||||
public static class IntegerFunctionProperty extends IntegerProperty {
|
||||
public IntegerFunctionProperty(String function, String columnName) {
|
||||
super(null, columnName, function);
|
||||
alias = columnName;
|
||||
}
|
||||
}
|
||||
|
||||
/** Counting in aggregated tables. Returns the result of COUNT(1) */
|
||||
public static final class CountProperty extends IntegerFunctionProperty {
|
||||
public CountProperty() {
|
||||
super("COUNT(1)", "count");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.data;
|
||||
|
||||
import com.todoroo.andlib.Field;
|
||||
import com.todoroo.andlib.SqlTable;
|
||||
|
||||
/**
|
||||
* Table class. Most fields are final, so methods such as <code>as</code> will
|
||||
* clone the table when it returns.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public final class Table extends SqlTable {
|
||||
public final String name;
|
||||
public final Class<? extends AbstractModel> modelClass;
|
||||
|
||||
public Table(String name, Class<? extends AbstractModel> modelClass) {
|
||||
this(name, modelClass, null);
|
||||
}
|
||||
|
||||
public Table(String name, Class<? extends AbstractModel> modelClass, String alias) {
|
||||
super(name);
|
||||
this.name = name;
|
||||
this.alias = alias;
|
||||
this.modelClass = modelClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a list of properties from model class by reflection
|
||||
* @return property array
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public Property<?>[] getProperties() {
|
||||
try {
|
||||
return (Property<?>[])modelClass.getField("PROPERTIES").get(null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (SecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// --- for sql-dsl
|
||||
|
||||
/**
|
||||
* Create a new join table based on this table, but with an alias
|
||||
*/
|
||||
@Override
|
||||
public Table as(String newAlias) {
|
||||
return new Table(name, modelClass, newAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a field object based on the given property
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public Field field(Property<?> property) {
|
||||
if(alias != null)
|
||||
return Field.field(alias + "." + property.name);
|
||||
return Field.field(name + "." + property.name);
|
||||
}
|
||||
}
|
@ -1,382 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.data;
|
||||
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import com.todoroo.andlib.DateUtilities;
|
||||
import com.todoroo.astrid.data.Property.IntegerProperty;
|
||||
import com.todoroo.astrid.data.Property.LongProperty;
|
||||
import com.todoroo.astrid.data.Property.StringProperty;
|
||||
|
||||
/**
|
||||
* Data Model which represents a task users need to accomplish.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public final class Task extends AbstractModel {
|
||||
|
||||
// --- table
|
||||
|
||||
public static final Table TABLE = new Table("tasks", Task.class);
|
||||
|
||||
// --- properties
|
||||
|
||||
/** ID */
|
||||
public static final LongProperty ID = new LongProperty(
|
||||
TABLE, ID_PROPERTY_NAME);
|
||||
|
||||
/** Name of Task */
|
||||
public static final StringProperty TITLE = new StringProperty(
|
||||
TABLE, "title");
|
||||
|
||||
/** Importance of Task (see importance flags) */
|
||||
public static final IntegerProperty IMPORTANCE = new IntegerProperty(
|
||||
TABLE, "importance");
|
||||
|
||||
/** Unixtime Task is due, 0 if not set */
|
||||
public static final LongProperty DUE_DATE = new LongProperty(
|
||||
TABLE, "dueDate");
|
||||
|
||||
/** Unixtime Task should be hidden until, 0 if not set */
|
||||
public static final LongProperty HIDE_UNTIL = new LongProperty(
|
||||
TABLE, "hideUntil");
|
||||
|
||||
/** Unixtime Task was created */
|
||||
public static final LongProperty CREATION_DATE = new LongProperty(
|
||||
TABLE, "created");
|
||||
|
||||
/** Unixtime Task was last touched */
|
||||
public static final LongProperty MODIFICATION_DATE = new LongProperty(
|
||||
TABLE, "modified");
|
||||
|
||||
/** Unixtime Task was completed. 0 means active */
|
||||
public static final LongProperty COMPLETION_DATE = new LongProperty(
|
||||
TABLE, "completed");
|
||||
|
||||
/** Unixtime Task was deleted. 0 means not deleted */
|
||||
public static final LongProperty DELETION_DATE = new LongProperty(
|
||||
TABLE, "deleted");
|
||||
|
||||
// --- for migration purposes from astrid 2 (eventually we will want to
|
||||
// move these into the metadata table and treat them as plug-ins
|
||||
|
||||
public static final StringProperty NOTES = new StringProperty(
|
||||
TABLE, "notes");
|
||||
|
||||
public static final IntegerProperty ESTIMATED_SECONDS = new IntegerProperty(
|
||||
TABLE, "estimatedSeconds");
|
||||
|
||||
public static final IntegerProperty ELAPSED_SECONDS = new IntegerProperty(
|
||||
TABLE, "elapsedSeconds");
|
||||
|
||||
public static final LongProperty TIMER_START = new LongProperty(
|
||||
TABLE, "timerStart");
|
||||
|
||||
public static final IntegerProperty POSTPONE_COUNT = new IntegerProperty(
|
||||
TABLE, "postponeCount");
|
||||
|
||||
/** Flags for when to send reminders */
|
||||
public static final IntegerProperty REMINDER_FLAGS = new IntegerProperty(
|
||||
TABLE, "notificationFlags");
|
||||
|
||||
/** Reminder period, in milliseconds. 0 means disabled */
|
||||
public static final LongProperty REMINDER_PERIOD = new LongProperty(
|
||||
TABLE, "notifications");
|
||||
|
||||
/** Unixtime the last reminder was triggered */
|
||||
public static final LongProperty REMINDER_LAST = new LongProperty(
|
||||
TABLE, "lastNotified");
|
||||
|
||||
public static final StringProperty RECURRENCE = new StringProperty(
|
||||
TABLE, "recurrence");
|
||||
|
||||
public static final IntegerProperty FLAGS = new IntegerProperty(
|
||||
TABLE, "flags");
|
||||
|
||||
public static final StringProperty CALENDAR_URI = new StringProperty(
|
||||
TABLE, "calendarUri");
|
||||
|
||||
/** List of all properties for this model */
|
||||
public static final Property<?>[] PROPERTIES = generateProperties(Task.class);
|
||||
|
||||
// --- flags
|
||||
|
||||
/** whether repeat occurs relative to completion date instead of due date */
|
||||
public static final int FLAG_REPEAT_AFTER_COMPLETION = 1 << 1;
|
||||
|
||||
// --- notification flags
|
||||
|
||||
/** whether to send a reminder at deadline */
|
||||
public static final int NOTIFY_AT_DEADLINE = 1 << 1;
|
||||
|
||||
/** whether to send reminders while task is overdue */
|
||||
public static final int NOTIFY_AFTER_DEADLINE = 1 << 2;
|
||||
|
||||
/** reminder mode non-stop */
|
||||
public static final int NOTIFY_NONSTOP = 1 << 3;
|
||||
|
||||
// --- importance settings
|
||||
|
||||
public static final int IMPORTANCE_DO_OR_DIE = 0;
|
||||
public static final int IMPORTANCE_MUST_DO = 1;
|
||||
public static final int IMPORTANCE_SHOULD_DO = 2;
|
||||
public static final int IMPORTANCE_NONE = 3;
|
||||
|
||||
public static final int IMPORTANCE_MOST = IMPORTANCE_DO_OR_DIE;
|
||||
public static final int IMPORTANCE_LEAST = IMPORTANCE_NONE;
|
||||
|
||||
// --- defaults
|
||||
|
||||
/** Default values container */
|
||||
private static final ContentValues defaultValues = new ContentValues();
|
||||
|
||||
static {
|
||||
defaultValues.put(TITLE.name, "");
|
||||
defaultValues.put(DUE_DATE.name, 0);
|
||||
defaultValues.put(HIDE_UNTIL.name, 0);
|
||||
defaultValues.put(COMPLETION_DATE.name, 0);
|
||||
defaultValues.put(DELETION_DATE.name, 0);
|
||||
defaultValues.put(IMPORTANCE.name, IMPORTANCE_NONE);
|
||||
|
||||
defaultValues.put(CALENDAR_URI.name, "");
|
||||
defaultValues.put(RECURRENCE.name, "");
|
||||
defaultValues.put(REMINDER_PERIOD.name, 0);
|
||||
defaultValues.put(REMINDER_FLAGS.name, 0);
|
||||
defaultValues.put(ESTIMATED_SECONDS.name, 0);
|
||||
defaultValues.put(ELAPSED_SECONDS.name, 0);
|
||||
defaultValues.put(POSTPONE_COUNT.name, 0);
|
||||
defaultValues.put(NOTES.name, "");
|
||||
defaultValues.put(FLAGS.name, 0);
|
||||
defaultValues.put(TIMER_START.name, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentValues getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
// --- data access boilerplate
|
||||
|
||||
public Task() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Task(TodorooCursor<Task> cursor) {
|
||||
this();
|
||||
readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
public void readFromCursor(TodorooCursor<Task> cursor) {
|
||||
super.readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return getIdHelper(ID);
|
||||
}
|
||||
|
||||
// --- parcelable helpers
|
||||
|
||||
private static final Creator<Task> CREATOR = new ModelCreator<Task>(Task.class);
|
||||
|
||||
@Override
|
||||
protected Creator<? extends AbstractModel> getCreator() {
|
||||
return CREATOR;
|
||||
}
|
||||
|
||||
// --- data access methods
|
||||
|
||||
/** Checks whether task is done. Requires COMPLETION_DATE */
|
||||
public boolean isCompleted() {
|
||||
return getValue(COMPLETION_DATE) > 0;
|
||||
}
|
||||
|
||||
/** Checks whether task is deleted. Will return false if DELETION_DATE not read */
|
||||
public boolean isDeleted() {
|
||||
// assume false if we didn't load deletion date
|
||||
if(!containsValue(DELETION_DATE))
|
||||
return false;
|
||||
else
|
||||
return getValue(DELETION_DATE) > 0;
|
||||
}
|
||||
|
||||
/** Checks whether task is hidden. Requires HIDDEN_UNTIL */
|
||||
public boolean isHidden() {
|
||||
return getValue(HIDE_UNTIL) > DateUtilities.now();
|
||||
}
|
||||
|
||||
/** Checks whether task is done. Requires DUE_DATE */
|
||||
public boolean hasDueDate() {
|
||||
return getValue(DUE_DATE) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set state of the given flag on the given property
|
||||
* @param property
|
||||
* @param flag
|
||||
* @return
|
||||
*/
|
||||
public boolean getFlag(IntegerProperty property, int flag) {
|
||||
return (getValue(property) & flag) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of the given flag on the given property
|
||||
* @param property
|
||||
* @param flag
|
||||
* @param value
|
||||
*/
|
||||
public void setFlag(IntegerProperty property, int flag, boolean value) {
|
||||
if(value)
|
||||
setValue(property, getValue(property) | flag);
|
||||
else
|
||||
setValue(property, getValue(property) & ~flag);
|
||||
}
|
||||
|
||||
// --- due and hide until date management
|
||||
|
||||
/** urgency array index -> significance */
|
||||
public static final int URGENCY_NONE = 0;
|
||||
public static final int URGENCY_TODAY = 1;
|
||||
public static final int URGENCY_TOMORROW = 2;
|
||||
public static final int URGENCY_DAY_AFTER = 3;
|
||||
public static final int URGENCY_NEXT_WEEK = 4;
|
||||
public static final int URGENCY_NEXT_MONTH = 5;
|
||||
public static final int URGENCY_SPECIFIC_DAY = 6;
|
||||
public static final int URGENCY_SPECIFIC_DAY_TIME = 7;
|
||||
|
||||
/** hide until array index -> significance */
|
||||
public static final int HIDE_UNTIL_NONE = 0;
|
||||
public static final int HIDE_UNTIL_DUE = 1;
|
||||
public static final int HIDE_UNTIL_DAY_BEFORE = 2;
|
||||
public static final int HIDE_UNTIL_WEEK_BEFORE = 3;
|
||||
public static final int HIDE_UNTIL_SPECIFIC_DAY = 4;
|
||||
|
||||
/**
|
||||
* Creates due date for this task. If this due date has no time associated,
|
||||
* we move it to the last millisecond of the day.
|
||||
*
|
||||
* @param setting
|
||||
* one of the URGENCY_* constants
|
||||
* @param customDate
|
||||
* if specific day or day & time is set, this value
|
||||
*/
|
||||
public long createDueDate(int setting, long customDate) {
|
||||
long date;
|
||||
|
||||
switch(setting) {
|
||||
case URGENCY_NONE:
|
||||
date = 0;
|
||||
break;
|
||||
case URGENCY_TODAY:
|
||||
date = DateUtilities.now();
|
||||
break;
|
||||
case URGENCY_TOMORROW:
|
||||
date = DateUtilities.now() + DateUtilities.ONE_DAY;
|
||||
break;
|
||||
case URGENCY_DAY_AFTER:
|
||||
date = DateUtilities.now() + 2 * DateUtilities.ONE_DAY;
|
||||
break;
|
||||
case URGENCY_NEXT_WEEK:
|
||||
date = DateUtilities.now() + DateUtilities.ONE_WEEK;
|
||||
break;
|
||||
case URGENCY_NEXT_MONTH:
|
||||
date = DateUtilities.oneMonthFromNow();
|
||||
break;
|
||||
case URGENCY_SPECIFIC_DAY:
|
||||
case URGENCY_SPECIFIC_DAY_TIME:
|
||||
date = customDate;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown setting " + setting);
|
||||
}
|
||||
|
||||
if(date <= 0)
|
||||
return date;
|
||||
|
||||
Date dueDate = new Date(date / 1000L * 1000L); // get rid of millis
|
||||
if(setting != URGENCY_SPECIFIC_DAY_TIME) {
|
||||
dueDate.setHours(23);
|
||||
dueDate.setMinutes(59);
|
||||
dueDate.setSeconds(59);
|
||||
} else if(isEndOfDay(dueDate)) {
|
||||
dueDate.setSeconds(58);
|
||||
}
|
||||
return dueDate.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create hide until for this task.
|
||||
*
|
||||
* @param setting
|
||||
* one of the HIDE_UNTIL_* constants
|
||||
* @param customDate
|
||||
* if specific day is set, this value
|
||||
* @return
|
||||
*/
|
||||
public long createHideUntil(int setting, long customDate) {
|
||||
long date;
|
||||
|
||||
switch(setting) {
|
||||
case HIDE_UNTIL_NONE:
|
||||
return 0;
|
||||
case HIDE_UNTIL_DUE:
|
||||
date = getValue(DUE_DATE);
|
||||
break;
|
||||
case HIDE_UNTIL_DAY_BEFORE:
|
||||
date = getValue(DUE_DATE) - DateUtilities.ONE_DAY;
|
||||
break;
|
||||
case HIDE_UNTIL_WEEK_BEFORE:
|
||||
date = getValue(DUE_DATE) - DateUtilities.ONE_WEEK;
|
||||
break;
|
||||
case HIDE_UNTIL_SPECIFIC_DAY:
|
||||
date = customDate;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown setting " + setting);
|
||||
}
|
||||
|
||||
if(date <= 0)
|
||||
return date;
|
||||
|
||||
Date hideUntil = new Date(date / 1000L * 1000L); // get rid of millis
|
||||
hideUntil.setHours(0);
|
||||
hideUntil.setMinutes(0);
|
||||
hideUntil.setSeconds(0);
|
||||
return hideUntil.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if hours, minutes, and seconds indicate end of day
|
||||
*/
|
||||
private static boolean isEndOfDay(Date date) {
|
||||
int hours = date.getHours();
|
||||
int minutes = date.getMinutes();
|
||||
int seconds = date.getSeconds();
|
||||
return hours == 23 && minutes == 59 && seconds == 59;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this due date has a due time or only a date
|
||||
*/
|
||||
public boolean hasDueTime() {
|
||||
return hasDueTime(getDUE_DATE());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether provided due date has a due time or only a date
|
||||
*/
|
||||
public static boolean hasDueTime(long dueDate) {
|
||||
return !isEndOfDay(new Date(dueDate));
|
||||
}
|
||||
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.data;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.CursorWrapper;
|
||||
|
||||
import com.todoroo.astrid.data.Property.PropertyVisitor;
|
||||
|
||||
/**
|
||||
* AstridCursor wraps a cursor and allows users to query for individual
|
||||
* {@link Property} types or read an entire {@link AbstractModel} from
|
||||
* a database row.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
* @param <TYPE> a model type that is returned by this cursor
|
||||
*/
|
||||
public class TodorooCursor<TYPE extends AbstractModel> extends CursorWrapper {
|
||||
|
||||
/** Properties read by this cursor */
|
||||
private final Property<?>[] properties;
|
||||
|
||||
/** Weakly cache field name to column id references for this cursor.
|
||||
* Because it's a weak hash map, entire keys can be discarded by GC */
|
||||
private final WeakHashMap<String, Integer> columnIndexCache;
|
||||
|
||||
/** Property reading visitor */
|
||||
private static final CursorReadingVisitor reader = new CursorReadingVisitor();
|
||||
|
||||
/**
|
||||
* Create an <code>AstridCursor</code> from the supplied {@link Cursor}
|
||||
* object.
|
||||
*
|
||||
* @param cursor
|
||||
* @param properties properties read from this cursor
|
||||
*/
|
||||
public TodorooCursor(Cursor cursor, Property<?>[] properties) {
|
||||
super(cursor);
|
||||
|
||||
this.properties = properties;
|
||||
columnIndexCache = new WeakHashMap<String, Integer>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the given property on the underlying {@link Cursor}
|
||||
*
|
||||
* @param <PROPERTY_TYPE> type to return
|
||||
* @param property to retrieve
|
||||
* @return
|
||||
*/
|
||||
public <PROPERTY_TYPE> PROPERTY_TYPE get(Property<PROPERTY_TYPE> property) {
|
||||
return (PROPERTY_TYPE)property.accept(reader, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets entire property list
|
||||
* @return
|
||||
*/
|
||||
public Property<?>[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use cache to get the column index for the given field name
|
||||
*/
|
||||
public synchronized int getColumnIndexFromCache(String field) {
|
||||
Integer index = columnIndexCache.get(field);
|
||||
if(index == null) {
|
||||
index = getColumnIndexOrThrow(field);
|
||||
columnIndexCache.put(field, index);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visitor that reads the given property from a cursor
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public static class CursorReadingVisitor implements PropertyVisitor<Object, TodorooCursor<?>> {
|
||||
|
||||
public Object visitDouble(Property<Double> property,
|
||||
TodorooCursor<?> cursor) {
|
||||
return cursor.getDouble(cursor.getColumnIndexFromCache(property.name));
|
||||
}
|
||||
|
||||
public Object visitInteger(Property<Integer> property,
|
||||
TodorooCursor<?> cursor) {
|
||||
return cursor.getInt(cursor.getColumnIndexFromCache(property.name));
|
||||
}
|
||||
|
||||
public Object visitLong(Property<Long> property, TodorooCursor<?> cursor) {
|
||||
return cursor.getLong(cursor.getColumnIndexFromCache(property.name));
|
||||
}
|
||||
|
||||
public Object visitString(Property<String> property,
|
||||
TodorooCursor<?> cursor) {
|
||||
return cursor.getString(cursor.getColumnIndexFromCache(property.name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue