mirror of https://github.com/tasks/tasks
Fix CRLF for dev
parent
d1ccce4e68
commit
d7f17502fe
@ -1,39 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>astrid</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>astrid</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
|
@ -1,89 +1,89 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.AND;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.EXISTS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.NOT;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.OR;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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();
|
||||
}
|
||||
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.AND;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.EXISTS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.NOT;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.OR;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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,67 +1,67 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.AS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
|
||||
public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
|
||||
protected String alias;
|
||||
protected final String expression;
|
||||
|
||||
protected DBObject(String expression){
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.AS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
|
||||
public abstract class DBObject<T extends DBObject<?>> implements Cloneable {
|
||||
protected String alias;
|
||||
protected final String expression;
|
||||
|
||||
protected DBObject(String expression){
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
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,7 +1,7 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public class EqCriterion extends UnaryCriterion {
|
||||
EqCriterion(Field field, Object value) {
|
||||
super(field, Operator.eq, value);
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public class EqCriterion extends UnaryCriterion {
|
||||
EqCriterion(Field field, Object value) {
|
||||
super(field, Operator.eq, value);
|
||||
}
|
||||
}
|
||||
|
@ -1,90 +1,90 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.AND;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.BETWEEN;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.AND;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.BETWEEN;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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,14 +1,14 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
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,43 +1,43 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.JOIN;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ON;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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();
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.JOIN;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ON;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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,5 +1,5 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public enum JoinType {
|
||||
INNER, LEFT, RIGHT, OUT
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public enum JoinType {
|
||||
INNER, LEFT, RIGHT, OUT
|
||||
}
|
||||
|
@ -1,57 +1,57 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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();
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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,30 +1,30 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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;
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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,5 +1,5 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public enum OrderType {
|
||||
DESC, ASC
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
public enum OrderType {
|
||||
DESC, ASC
|
||||
}
|
||||
|
@ -1,205 +1,205 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ALL;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.FROM;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.GROUP_BY;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LIMIT;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ORDER_BY;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SELECT;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.WHERE;
|
||||
import static com.todoroo.andlib.sql.SqlTable.table;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.todoroo.andlib.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 int limits = -1;
|
||||
|
||||
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 limit(int limit) {
|
||||
limits = limit;
|
||||
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);
|
||||
visitLimitClause(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);
|
||||
}
|
||||
|
||||
private void visitLimitClause(StringBuilder sql) {
|
||||
if(limits > -1)
|
||||
sql.append(LIMIT).append(SPACE).append(limits).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;
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ALL;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.FROM;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.GROUP_BY;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LIMIT;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ORDER_BY;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SELECT;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.WHERE;
|
||||
import static com.todoroo.andlib.sql.SqlTable.table;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.todoroo.andlib.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 int limits = -1;
|
||||
|
||||
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 limit(int limit) {
|
||||
limits = limit;
|
||||
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);
|
||||
visitLimitClause(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);
|
||||
}
|
||||
|
||||
private void visitLimitClause(StringBuilder sql) {
|
||||
if(limits > -1)
|
||||
sql.append(LIMIT).append(SPACE).append(limits).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,117 +1,117 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.GROUP_BY;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LIMIT;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ORDER_BY;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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;
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.COMMA;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.GROUP_BY;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.LIMIT;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.ORDER_BY;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.SPACE;
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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 +1,25 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public final class SqlConstants {
|
||||
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";
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public final class SqlConstants {
|
||||
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,20 +1,20 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
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,92 +1,92 @@
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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("'", "''");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib.sql;
|
||||
|
||||
import static com.todoroo.andlib.sql.SqlConstants.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("'", "''");
|
||||
}
|
||||
|
||||
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,146 +1,146 @@
|
||||
package com.todoroo.astrid.gcal;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.utility.AndroidUtilities;
|
||||
import com.todoroo.astrid.utility.Preferences;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public class Calendars {
|
||||
|
||||
public static final String CALENDAR_CONTENT_CALENDARS = "calendars";
|
||||
public static final String CALENDAR_CONTENT_EVENTS = "events";
|
||||
|
||||
private static final String ID_COLUMN_NAME = "_id";
|
||||
private static final String DISPLAY_COLUMN_NAME = "displayName";
|
||||
private static final String ACCES_LEVEL_COLUMN_NAME = "access_level";
|
||||
|
||||
private static final String[] CALENDARS_PROJECTION = new String[] {
|
||||
ID_COLUMN_NAME, // Calendars._ID,
|
||||
DISPLAY_COLUMN_NAME // Calendars.DISPLAY_NAME
|
||||
};
|
||||
|
||||
// Only show calendars that the user can modify. Access level 500
|
||||
// corresponds to Calendars.CONTRIBUTOR_ACCESS
|
||||
private static final String CALENDARS_WHERE = ACCES_LEVEL_COLUMN_NAME + ">= 500";
|
||||
|
||||
private static final String CALENDARS_SORT = "displayName ASC";
|
||||
|
||||
// --- api access
|
||||
|
||||
/** Return content uri for calendars
|
||||
* @param table provider table, something like calendars, events
|
||||
*/
|
||||
public static Uri getCalendarContentUri(String table) {
|
||||
if(AndroidUtilities.getSdkVersion() >= 8)
|
||||
return Uri.parse("content://com.android.calendar/" + table);
|
||||
else
|
||||
return Uri.parse("content://calendar/" + table);
|
||||
}
|
||||
|
||||
/** Return calendar package name */
|
||||
public static String getCalendarPackage() {
|
||||
if(AndroidUtilities.getSdkVersion() >= 8)
|
||||
return "com.google.android.calendar";
|
||||
else
|
||||
return "com.android.calendar";
|
||||
}
|
||||
|
||||
// --- helper data structure
|
||||
|
||||
/**
|
||||
* Helper class for working with the results of getCalendars
|
||||
*/
|
||||
public static class CalendarResult {
|
||||
/** calendar names */
|
||||
public String[] calendars;
|
||||
|
||||
/** calendar ids. null entry -> use default */
|
||||
public String[] calendarIds;
|
||||
|
||||
/** default selection index */
|
||||
public int defaultIndex = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends all user-modifiable calendars to listPreference. Always includes
|
||||
* entry called "Astrid default" with calendar id of
|
||||
* prefs_defaultCalendar_default.
|
||||
*
|
||||
* @param context
|
||||
* context
|
||||
* @param listPreference
|
||||
* preference to init
|
||||
*/
|
||||
public static CalendarResult getCalendars() {
|
||||
Context context = ContextManager.getContext();
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
Resources r = context.getResources();
|
||||
Cursor c = cr.query(getCalendarContentUri(CALENDAR_CONTENT_CALENDARS), CALENDARS_PROJECTION,
|
||||
CALENDARS_WHERE, null, CALENDARS_SORT);
|
||||
try {
|
||||
// Fetch the current setting. Invalid calendar id will
|
||||
// be changed to default value.
|
||||
String defaultSetting = Preferences.getStringValue(R.string.gcal_p_default);
|
||||
|
||||
CalendarResult result = new CalendarResult();
|
||||
|
||||
if (c == null || c.getCount() == 0) {
|
||||
// Something went wrong when querying calendars. Only offer them
|
||||
// the system default choice
|
||||
result.calendars = new String[] {
|
||||
r.getString(R.string.gcal_GCP_default) };
|
||||
result.calendarIds = new String[] { null };
|
||||
result.defaultIndex = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int calendarCount = c.getCount();
|
||||
|
||||
result.calendars = new String[calendarCount];
|
||||
result.calendarIds = new String[calendarCount];
|
||||
|
||||
// Iterate calendars one by one, and fill up the list preference
|
||||
int row = 0;
|
||||
int idColumn = c.getColumnIndex(ID_COLUMN_NAME);
|
||||
int nameColumn = c.getColumnIndex(DISPLAY_COLUMN_NAME);
|
||||
while (c.moveToNext()) {
|
||||
String id = c.getString(idColumn);
|
||||
String name = c.getString(nameColumn);
|
||||
result.calendars[row] = name;
|
||||
result.calendarIds[row] = id;
|
||||
|
||||
// We found currently selected calendar
|
||||
if (defaultSetting != null && defaultSetting.equals(id)) {
|
||||
result.defaultIndex = row;
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
|
||||
if (result.defaultIndex == -1 || result.defaultIndex >= calendarCount) {
|
||||
result.defaultIndex = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
if(c != null)
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the default calendar for future use
|
||||
* @param defaultCalendar default calendar id
|
||||
*/
|
||||
public static void setDefaultCalendar(String defaultCalendar) {
|
||||
Preferences.setString(R.string.gcal_p_default, defaultCalendar);
|
||||
}
|
||||
|
||||
package com.todoroo.astrid.gcal;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.utility.AndroidUtilities;
|
||||
import com.todoroo.astrid.utility.Preferences;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public class Calendars {
|
||||
|
||||
public static final String CALENDAR_CONTENT_CALENDARS = "calendars";
|
||||
public static final String CALENDAR_CONTENT_EVENTS = "events";
|
||||
|
||||
private static final String ID_COLUMN_NAME = "_id";
|
||||
private static final String DISPLAY_COLUMN_NAME = "displayName";
|
||||
private static final String ACCES_LEVEL_COLUMN_NAME = "access_level";
|
||||
|
||||
private static final String[] CALENDARS_PROJECTION = new String[] {
|
||||
ID_COLUMN_NAME, // Calendars._ID,
|
||||
DISPLAY_COLUMN_NAME // Calendars.DISPLAY_NAME
|
||||
};
|
||||
|
||||
// Only show calendars that the user can modify. Access level 500
|
||||
// corresponds to Calendars.CONTRIBUTOR_ACCESS
|
||||
private static final String CALENDARS_WHERE = ACCES_LEVEL_COLUMN_NAME + ">= 500";
|
||||
|
||||
private static final String CALENDARS_SORT = "displayName ASC";
|
||||
|
||||
// --- api access
|
||||
|
||||
/** Return content uri for calendars
|
||||
* @param table provider table, something like calendars, events
|
||||
*/
|
||||
public static Uri getCalendarContentUri(String table) {
|
||||
if(AndroidUtilities.getSdkVersion() >= 8)
|
||||
return Uri.parse("content://com.android.calendar/" + table);
|
||||
else
|
||||
return Uri.parse("content://calendar/" + table);
|
||||
}
|
||||
|
||||
/** Return calendar package name */
|
||||
public static String getCalendarPackage() {
|
||||
if(AndroidUtilities.getSdkVersion() >= 8)
|
||||
return "com.google.android.calendar";
|
||||
else
|
||||
return "com.android.calendar";
|
||||
}
|
||||
|
||||
// --- helper data structure
|
||||
|
||||
/**
|
||||
* Helper class for working with the results of getCalendars
|
||||
*/
|
||||
public static class CalendarResult {
|
||||
/** calendar names */
|
||||
public String[] calendars;
|
||||
|
||||
/** calendar ids. null entry -> use default */
|
||||
public String[] calendarIds;
|
||||
|
||||
/** default selection index */
|
||||
public int defaultIndex = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends all user-modifiable calendars to listPreference. Always includes
|
||||
* entry called "Astrid default" with calendar id of
|
||||
* prefs_defaultCalendar_default.
|
||||
*
|
||||
* @param context
|
||||
* context
|
||||
* @param listPreference
|
||||
* preference to init
|
||||
*/
|
||||
public static CalendarResult getCalendars() {
|
||||
Context context = ContextManager.getContext();
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
Resources r = context.getResources();
|
||||
Cursor c = cr.query(getCalendarContentUri(CALENDAR_CONTENT_CALENDARS), CALENDARS_PROJECTION,
|
||||
CALENDARS_WHERE, null, CALENDARS_SORT);
|
||||
try {
|
||||
// Fetch the current setting. Invalid calendar id will
|
||||
// be changed to default value.
|
||||
String defaultSetting = Preferences.getStringValue(R.string.gcal_p_default);
|
||||
|
||||
CalendarResult result = new CalendarResult();
|
||||
|
||||
if (c == null || c.getCount() == 0) {
|
||||
// Something went wrong when querying calendars. Only offer them
|
||||
// the system default choice
|
||||
result.calendars = new String[] {
|
||||
r.getString(R.string.gcal_GCP_default) };
|
||||
result.calendarIds = new String[] { null };
|
||||
result.defaultIndex = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int calendarCount = c.getCount();
|
||||
|
||||
result.calendars = new String[calendarCount];
|
||||
result.calendarIds = new String[calendarCount];
|
||||
|
||||
// Iterate calendars one by one, and fill up the list preference
|
||||
int row = 0;
|
||||
int idColumn = c.getColumnIndex(ID_COLUMN_NAME);
|
||||
int nameColumn = c.getColumnIndex(DISPLAY_COLUMN_NAME);
|
||||
while (c.moveToNext()) {
|
||||
String id = c.getString(idColumn);
|
||||
String name = c.getString(nameColumn);
|
||||
result.calendars[row] = name;
|
||||
result.calendarIds[row] = id;
|
||||
|
||||
// We found currently selected calendar
|
||||
if (defaultSetting != null && defaultSetting.equals(id)) {
|
||||
result.defaultIndex = row;
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
|
||||
if (result.defaultIndex == -1 || result.defaultIndex >= calendarCount) {
|
||||
result.defaultIndex = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
if(c != null)
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the default calendar for future use
|
||||
* @param defaultCalendar default calendar id
|
||||
*/
|
||||
public static void setDefaultCalendar(String defaultCalendar) {
|
||||
Preferences.setString(R.string.gcal_p_default, defaultCalendar);
|
||||
}
|
||||
|
||||
}
|
@ -1,95 +1,95 @@
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.producteev;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.astrid.adapter.TaskAdapter;
|
||||
import com.todoroo.astrid.api.AstridApiConstants;
|
||||
import com.todoroo.astrid.api.DetailExposer;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevNote;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevTask;
|
||||
|
||||
/**
|
||||
* Exposes Task Details for Producteev:
|
||||
* - notes
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class ProducteevDetailExposer extends BroadcastReceiver implements DetailExposer{
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// if we aren't logged in, don't expose features
|
||||
if(!ProducteevUtilities.INSTANCE.isLoggedIn())
|
||||
return;
|
||||
|
||||
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
|
||||
if(taskId == -1)
|
||||
return;
|
||||
|
||||
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
|
||||
String taskDetail = getTaskDetails(context, taskId, extended);
|
||||
if(taskDetail == null)
|
||||
return;
|
||||
|
||||
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, ProducteevUtilities.IDENTIFIER);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
|
||||
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTaskDetails(Context context, long id, boolean extended) {
|
||||
Metadata metadata = ProducteevDataService.getInstance().getTaskMetadata(id);
|
||||
if(metadata == null)
|
||||
return null;
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if(!extended) {
|
||||
long dashboardId = metadata.getValue(ProducteevTask.DASHBOARD_ID);
|
||||
String dashboardName = ProducteevDataService.getInstance().getDashboardName(dashboardId);
|
||||
// Prod dashboard is out of date. don't display Producteev stuff
|
||||
if(dashboardName == null)
|
||||
return null;
|
||||
|
||||
if(dashboardId > 0) {
|
||||
builder.append(context.getString(R.string.producteev_TLA_dashboard,
|
||||
dashboardId)).append(TaskAdapter.DETAIL_SEPARATOR);
|
||||
}
|
||||
|
||||
} else {
|
||||
TodorooCursor<Metadata> notesCursor = ProducteevDataService.getInstance().getTaskNotesCursor(id);
|
||||
try {
|
||||
for(notesCursor.moveToFirst(); !notesCursor.isAfterLast(); notesCursor.moveToNext()) {
|
||||
metadata.readFromCursor(notesCursor);
|
||||
builder.append(metadata.getValue(ProducteevNote.MESSAGE)).append(TaskAdapter.DETAIL_SEPARATOR);
|
||||
}
|
||||
} finally {
|
||||
notesCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
if(builder.length() == 0)
|
||||
return null;
|
||||
String result = builder.toString();
|
||||
return result.substring(0, result.length() - TaskAdapter.DETAIL_SEPARATOR.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginIdentifier() {
|
||||
return ProducteevUtilities.IDENTIFIER;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.producteev;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.astrid.adapter.TaskAdapter;
|
||||
import com.todoroo.astrid.api.AstridApiConstants;
|
||||
import com.todoroo.astrid.api.DetailExposer;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevNote;
|
||||
import com.todoroo.astrid.producteev.sync.ProducteevTask;
|
||||
|
||||
/**
|
||||
* Exposes Task Details for Producteev:
|
||||
* - notes
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class ProducteevDetailExposer extends BroadcastReceiver implements DetailExposer{
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// if we aren't logged in, don't expose features
|
||||
if(!ProducteevUtilities.INSTANCE.isLoggedIn())
|
||||
return;
|
||||
|
||||
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
|
||||
if(taskId == -1)
|
||||
return;
|
||||
|
||||
boolean extended = intent.getBooleanExtra(AstridApiConstants.EXTRAS_EXTENDED, false);
|
||||
String taskDetail = getTaskDetails(context, taskId, extended);
|
||||
if(taskDetail == null)
|
||||
return;
|
||||
|
||||
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, ProducteevUtilities.IDENTIFIER);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_EXTENDED, extended);
|
||||
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, taskDetail);
|
||||
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTaskDetails(Context context, long id, boolean extended) {
|
||||
Metadata metadata = ProducteevDataService.getInstance().getTaskMetadata(id);
|
||||
if(metadata == null)
|
||||
return null;
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if(!extended) {
|
||||
long dashboardId = metadata.getValue(ProducteevTask.DASHBOARD_ID);
|
||||
String dashboardName = ProducteevDataService.getInstance().getDashboardName(dashboardId);
|
||||
// Prod dashboard is out of date. don't display Producteev stuff
|
||||
if(dashboardName == null)
|
||||
return null;
|
||||
|
||||
if(dashboardId > 0) {
|
||||
builder.append(context.getString(R.string.producteev_TLA_dashboard,
|
||||
dashboardId)).append(TaskAdapter.DETAIL_SEPARATOR);
|
||||
}
|
||||
|
||||
} else {
|
||||
TodorooCursor<Metadata> notesCursor = ProducteevDataService.getInstance().getTaskNotesCursor(id);
|
||||
try {
|
||||
for(notesCursor.moveToFirst(); !notesCursor.isAfterLast(); notesCursor.moveToNext()) {
|
||||
metadata.readFromCursor(notesCursor);
|
||||
builder.append(metadata.getValue(ProducteevNote.MESSAGE)).append(TaskAdapter.DETAIL_SEPARATOR);
|
||||
}
|
||||
} finally {
|
||||
notesCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
if(builder.length() == 0)
|
||||
return null;
|
||||
String result = builder.toString();
|
||||
return result.substring(0, result.length() - TaskAdapter.DETAIL_SEPARATOR.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginIdentifier() {
|
||||
return ProducteevUtilities.IDENTIFIER;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,86 +1,86 @@
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import com.todoroo.andlib.data.AbstractModel;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.Table;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.andlib.data.Property.StringProperty;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
|
||||
/**
|
||||
* Data Model which represents a dashboard in Producteev
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class ProducteevDashboard extends AbstractModel {
|
||||
|
||||
// --- table
|
||||
|
||||
public static final Table TABLE = new Table("dashboards", ProducteevDashboard.class);
|
||||
|
||||
// --- properties
|
||||
|
||||
/** ID (corresponds to RTM ID) */
|
||||
public static final LongProperty ID = new LongProperty(
|
||||
TABLE, ID_PROPERTY_NAME);
|
||||
|
||||
/** Name */
|
||||
public static final StringProperty NAME = new StringProperty(
|
||||
TABLE, "name");
|
||||
|
||||
/** List of all properties for this model */
|
||||
public static final Property<?>[] PROPERTIES = generateProperties(ProducteevDashboard.class);
|
||||
|
||||
// --- defaults
|
||||
|
||||
/** Default values container */
|
||||
private static final ContentValues defaultValues = new ContentValues();
|
||||
|
||||
// static {
|
||||
// defaultValues.put(POSITION.name, 0);
|
||||
// defaultValues.put(ARCHIVED.name, 0);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public ContentValues getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
// --- data access boilerplate
|
||||
|
||||
public ProducteevDashboard() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ProducteevDashboard(TodorooCursor<ProducteevDashboard> cursor) {
|
||||
this();
|
||||
readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
public void readFromCursor(TodorooCursor<ProducteevDashboard> 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;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import com.todoroo.andlib.data.AbstractModel;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.Table;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.andlib.data.Property.StringProperty;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
|
||||
/**
|
||||
* Data Model which represents a dashboard in Producteev
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class ProducteevDashboard extends AbstractModel {
|
||||
|
||||
// --- table
|
||||
|
||||
public static final Table TABLE = new Table("dashboards", ProducteevDashboard.class);
|
||||
|
||||
// --- properties
|
||||
|
||||
/** ID (corresponds to RTM ID) */
|
||||
public static final LongProperty ID = new LongProperty(
|
||||
TABLE, ID_PROPERTY_NAME);
|
||||
|
||||
/** Name */
|
||||
public static final StringProperty NAME = new StringProperty(
|
||||
TABLE, "name");
|
||||
|
||||
/** List of all properties for this model */
|
||||
public static final Property<?>[] PROPERTIES = generateProperties(ProducteevDashboard.class);
|
||||
|
||||
// --- defaults
|
||||
|
||||
/** Default values container */
|
||||
private static final ContentValues defaultValues = new ContentValues();
|
||||
|
||||
// static {
|
||||
// defaultValues.put(POSITION.name, 0);
|
||||
// defaultValues.put(ARCHIVED.name, 0);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public ContentValues getDefaultValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
// --- data access boilerplate
|
||||
|
||||
public ProducteevDashboard() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ProducteevDashboard(TodorooCursor<ProducteevDashboard> cursor) {
|
||||
this();
|
||||
readPropertiesFromCursor(cursor);
|
||||
}
|
||||
|
||||
public void readFromCursor(TodorooCursor<ProducteevDashboard> 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,235 +1,235 @@
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.todoroo.andlib.data.GenericDao;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.andlib.sql.Criterion;
|
||||
import com.todoroo.andlib.sql.Join;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.andlib.utility.SoftHashMap;
|
||||
import com.todoroo.astrid.dao.MetadataDao;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
|
||||
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
import com.todoroo.astrid.producteev.ProducteevUtilities;
|
||||
import com.todoroo.astrid.rmilk.data.MilkNote;
|
||||
import com.todoroo.astrid.tags.TagService;
|
||||
|
||||
public final class ProducteevDataService {
|
||||
|
||||
// --- constants
|
||||
|
||||
/** Utility for joining tasks with metadata */
|
||||
public static final Join METADATA_JOIN = Join.left(Metadata.TABLE, Task.ID.eq(Metadata.TASK));
|
||||
|
||||
// --- singleton
|
||||
|
||||
private static ProducteevDataService instance = null;
|
||||
|
||||
public static synchronized ProducteevDataService getInstance() {
|
||||
if(instance == null)
|
||||
instance = new ProducteevDataService(ContextManager.getContext());
|
||||
return instance;
|
||||
}
|
||||
|
||||
// --- instance variables
|
||||
|
||||
protected final Context context;
|
||||
|
||||
private final ProducteevDatabase prodDatabase = new ProducteevDatabase();
|
||||
|
||||
private final GenericDao<ProducteevDashboard> prodDashboardDao;
|
||||
|
||||
@Autowired
|
||||
private TaskDao taskDao;
|
||||
|
||||
@Autowired
|
||||
private MetadataDao metadataDao;
|
||||
|
||||
private final ProducteevUtilities preferences = ProducteevUtilities.INSTANCE;
|
||||
|
||||
static final Random random = new Random();
|
||||
|
||||
private ProducteevDataService(Context context) {
|
||||
this.context = context;
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
prodDashboardDao = new GenericDao<ProducteevDashboard>(ProducteevDashboard.class, prodDatabase);
|
||||
}
|
||||
|
||||
// --- task and metadata methods
|
||||
|
||||
/**
|
||||
* Clears RTM metadata information. Used when user logs out of RTM
|
||||
*/
|
||||
public void clearMetadata() {
|
||||
metadataDao.deleteWhere(Metadata.KEY.eq(ProducteevTask.METADATA_KEY));
|
||||
metadataDao.deleteWhere(Metadata.KEY.eq(ProducteevNote.METADATA_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tasks that were created since last sync
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
public TodorooCursor<Task> getLocallyCreated(Property<?>[] properties) {
|
||||
return
|
||||
taskDao.query(Query.select(properties).join(ProducteevDataService.METADATA_JOIN).where(Criterion.and(
|
||||
Criterion.not(Task.ID.in(Query.select(Metadata.TASK).from(Metadata.TABLE).
|
||||
where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY), ProducteevTask.ID.gt(0))))),
|
||||
TaskCriteria.isActive())).groupBy(Task.ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tasks that were modified since last sync
|
||||
* @param properties
|
||||
* @return null if never sync'd
|
||||
*/
|
||||
public TodorooCursor<Task> getLocallyUpdated(Property<?>[] properties) {
|
||||
long lastSyncDate = preferences.getLastSyncDate();
|
||||
if(lastSyncDate == 0)
|
||||
return taskDao.query(Query.select(Task.ID).where(Criterion.none));
|
||||
return
|
||||
taskDao.query(Query.select(properties).join(ProducteevDataService.METADATA_JOIN).
|
||||
where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
Task.MODIFICATION_DATE.gt(lastSyncDate))).groupBy(Task.ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a local task with same remote id, updates this task's id
|
||||
* @param remoteTask
|
||||
*/
|
||||
public void findLocalMatch(ProducteevTaskContainer remoteTask) {
|
||||
if(remoteTask.task.getId() != Task.NO_ID)
|
||||
return;
|
||||
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.ID).
|
||||
join(ProducteevDataService.METADATA_JOIN).where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
ProducteevTask.ID.eq(remoteTask.pdvTask.getValue(ProducteevTask.ID)))));
|
||||
try {
|
||||
if(cursor.getCount() == 0)
|
||||
return;
|
||||
cursor.moveToFirst();
|
||||
remoteTask.task.setId(cursor.get(Task.ID));
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a task and its metadata
|
||||
* @param task
|
||||
*/
|
||||
public void saveTaskAndMetadata(ProducteevTaskContainer task) {
|
||||
taskDao.save(task.task, true);
|
||||
|
||||
metadataDao.deleteWhere(Criterion.and(MetadataCriteria.byTask(task.task.getId()),
|
||||
Criterion.or(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY),
|
||||
MetadataCriteria.withKey(TagService.KEY))));
|
||||
task.metadata.add(task.pdvTask);
|
||||
task.pdvTask.setValue(Metadata.KEY, ProducteevTask.METADATA_KEY);
|
||||
for(Metadata metadata : task.metadata) {
|
||||
metadata.setValue(Metadata.TASK, task.task.getId());
|
||||
metadataDao.createNew(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a task and its metadata
|
||||
* @param task
|
||||
* @return
|
||||
*/
|
||||
public ProducteevTaskContainer readTaskAndMetadata(TodorooCursor<Task> taskCursor) {
|
||||
Task task = new Task(taskCursor);
|
||||
|
||||
// read tags, notes, etc
|
||||
ArrayList<Metadata> metadata = new ArrayList<Metadata>();
|
||||
TodorooCursor<Metadata> metadataCursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
|
||||
where(Criterion.and(MetadataCriteria.byTask(task.getId()),
|
||||
Criterion.or(MetadataCriteria.withKey(TagService.KEY),
|
||||
MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
// FIXME: Constant from other plugin shouldnt be used
|
||||
MetadataCriteria.withKey(MilkNote.METADATA_KEY),
|
||||
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY)))));
|
||||
try {
|
||||
for(metadataCursor.moveToFirst(); !metadataCursor.isAfterLast(); metadataCursor.moveToNext()) {
|
||||
metadata.add(new Metadata(metadataCursor));
|
||||
}
|
||||
} finally {
|
||||
metadataCursor.close();
|
||||
}
|
||||
|
||||
return new ProducteevTaskContainer(task, metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads metadata out of a task
|
||||
* @return null if no metadata found
|
||||
*/
|
||||
public Metadata getTaskMetadata(long taskId) {
|
||||
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(
|
||||
ProducteevTask.ID, ProducteevTask.DASHBOARD_ID).where(
|
||||
MetadataCriteria.byTaskAndwithKey(taskId, ProducteevTask.METADATA_KEY)));
|
||||
try {
|
||||
if(cursor.getCount() == 0)
|
||||
return null;
|
||||
cursor.moveToFirst();
|
||||
return new Metadata(cursor);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads task notes out of a task
|
||||
*/
|
||||
public TodorooCursor<Metadata> getTaskNotesCursor(long taskId) {
|
||||
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
|
||||
where(MetadataCriteria.byTaskAndwithKey(taskId, ProducteevNote.METADATA_KEY)));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
// --- list methods
|
||||
|
||||
private final Map<Long, String> dashboardCache =
|
||||
Collections.synchronizedMap(new SoftHashMap<Long, String>());
|
||||
|
||||
/**
|
||||
* Get dashboard name by dashboard id
|
||||
* @param dashboardId
|
||||
* @return null if no dashboard by this id exists, otherwise dashboard name
|
||||
*/
|
||||
public String getDashboardName(long dashboardId) {
|
||||
if(dashboardCache.containsKey(dashboardId))
|
||||
return dashboardCache.get(dashboardId);
|
||||
|
||||
TodorooCursor<ProducteevDashboard> cursor = prodDashboardDao.query(Query.select(
|
||||
ProducteevDashboard.NAME).where(ProducteevDashboard.ID.eq(dashboardId)));
|
||||
try {
|
||||
if(cursor.getCount() == 0) {
|
||||
dashboardCache.put(dashboardId, null);
|
||||
return null;
|
||||
}
|
||||
cursor.moveToFirst();
|
||||
String name = cursor.get(ProducteevDashboard.NAME);
|
||||
dashboardCache.put(dashboardId, name);
|
||||
return name;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.todoroo.andlib.data.GenericDao;
|
||||
import com.todoroo.andlib.data.Property;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.andlib.sql.Criterion;
|
||||
import com.todoroo.andlib.sql.Join;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.andlib.utility.SoftHashMap;
|
||||
import com.todoroo.astrid.dao.MetadataDao;
|
||||
import com.todoroo.astrid.dao.TaskDao;
|
||||
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
|
||||
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
import com.todoroo.astrid.producteev.ProducteevUtilities;
|
||||
import com.todoroo.astrid.rmilk.data.MilkNote;
|
||||
import com.todoroo.astrid.tags.TagService;
|
||||
|
||||
public final class ProducteevDataService {
|
||||
|
||||
// --- constants
|
||||
|
||||
/** Utility for joining tasks with metadata */
|
||||
public static final Join METADATA_JOIN = Join.left(Metadata.TABLE, Task.ID.eq(Metadata.TASK));
|
||||
|
||||
// --- singleton
|
||||
|
||||
private static ProducteevDataService instance = null;
|
||||
|
||||
public static synchronized ProducteevDataService getInstance() {
|
||||
if(instance == null)
|
||||
instance = new ProducteevDataService(ContextManager.getContext());
|
||||
return instance;
|
||||
}
|
||||
|
||||
// --- instance variables
|
||||
|
||||
protected final Context context;
|
||||
|
||||
private final ProducteevDatabase prodDatabase = new ProducteevDatabase();
|
||||
|
||||
private final GenericDao<ProducteevDashboard> prodDashboardDao;
|
||||
|
||||
@Autowired
|
||||
private TaskDao taskDao;
|
||||
|
||||
@Autowired
|
||||
private MetadataDao metadataDao;
|
||||
|
||||
private final ProducteevUtilities preferences = ProducteevUtilities.INSTANCE;
|
||||
|
||||
static final Random random = new Random();
|
||||
|
||||
private ProducteevDataService(Context context) {
|
||||
this.context = context;
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
prodDashboardDao = new GenericDao<ProducteevDashboard>(ProducteevDashboard.class, prodDatabase);
|
||||
}
|
||||
|
||||
// --- task and metadata methods
|
||||
|
||||
/**
|
||||
* Clears RTM metadata information. Used when user logs out of RTM
|
||||
*/
|
||||
public void clearMetadata() {
|
||||
metadataDao.deleteWhere(Metadata.KEY.eq(ProducteevTask.METADATA_KEY));
|
||||
metadataDao.deleteWhere(Metadata.KEY.eq(ProducteevNote.METADATA_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tasks that were created since last sync
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
public TodorooCursor<Task> getLocallyCreated(Property<?>[] properties) {
|
||||
return
|
||||
taskDao.query(Query.select(properties).join(ProducteevDataService.METADATA_JOIN).where(Criterion.and(
|
||||
Criterion.not(Task.ID.in(Query.select(Metadata.TASK).from(Metadata.TABLE).
|
||||
where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY), ProducteevTask.ID.gt(0))))),
|
||||
TaskCriteria.isActive())).groupBy(Task.ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tasks that were modified since last sync
|
||||
* @param properties
|
||||
* @return null if never sync'd
|
||||
*/
|
||||
public TodorooCursor<Task> getLocallyUpdated(Property<?>[] properties) {
|
||||
long lastSyncDate = preferences.getLastSyncDate();
|
||||
if(lastSyncDate == 0)
|
||||
return taskDao.query(Query.select(Task.ID).where(Criterion.none));
|
||||
return
|
||||
taskDao.query(Query.select(properties).join(ProducteevDataService.METADATA_JOIN).
|
||||
where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
Task.MODIFICATION_DATE.gt(lastSyncDate))).groupBy(Task.ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a local task with same remote id, updates this task's id
|
||||
* @param remoteTask
|
||||
*/
|
||||
public void findLocalMatch(ProducteevTaskContainer remoteTask) {
|
||||
if(remoteTask.task.getId() != Task.NO_ID)
|
||||
return;
|
||||
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.ID).
|
||||
join(ProducteevDataService.METADATA_JOIN).where(Criterion.and(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
ProducteevTask.ID.eq(remoteTask.pdvTask.getValue(ProducteevTask.ID)))));
|
||||
try {
|
||||
if(cursor.getCount() == 0)
|
||||
return;
|
||||
cursor.moveToFirst();
|
||||
remoteTask.task.setId(cursor.get(Task.ID));
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a task and its metadata
|
||||
* @param task
|
||||
*/
|
||||
public void saveTaskAndMetadata(ProducteevTaskContainer task) {
|
||||
taskDao.save(task.task, true);
|
||||
|
||||
metadataDao.deleteWhere(Criterion.and(MetadataCriteria.byTask(task.task.getId()),
|
||||
Criterion.or(MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY),
|
||||
MetadataCriteria.withKey(TagService.KEY))));
|
||||
task.metadata.add(task.pdvTask);
|
||||
task.pdvTask.setValue(Metadata.KEY, ProducteevTask.METADATA_KEY);
|
||||
for(Metadata metadata : task.metadata) {
|
||||
metadata.setValue(Metadata.TASK, task.task.getId());
|
||||
metadataDao.createNew(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a task and its metadata
|
||||
* @param task
|
||||
* @return
|
||||
*/
|
||||
public ProducteevTaskContainer readTaskAndMetadata(TodorooCursor<Task> taskCursor) {
|
||||
Task task = new Task(taskCursor);
|
||||
|
||||
// read tags, notes, etc
|
||||
ArrayList<Metadata> metadata = new ArrayList<Metadata>();
|
||||
TodorooCursor<Metadata> metadataCursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
|
||||
where(Criterion.and(MetadataCriteria.byTask(task.getId()),
|
||||
Criterion.or(MetadataCriteria.withKey(TagService.KEY),
|
||||
MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
|
||||
// FIXME: Constant from other plugin shouldnt be used
|
||||
MetadataCriteria.withKey(MilkNote.METADATA_KEY),
|
||||
MetadataCriteria.withKey(ProducteevNote.METADATA_KEY)))));
|
||||
try {
|
||||
for(metadataCursor.moveToFirst(); !metadataCursor.isAfterLast(); metadataCursor.moveToNext()) {
|
||||
metadata.add(new Metadata(metadataCursor));
|
||||
}
|
||||
} finally {
|
||||
metadataCursor.close();
|
||||
}
|
||||
|
||||
return new ProducteevTaskContainer(task, metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads metadata out of a task
|
||||
* @return null if no metadata found
|
||||
*/
|
||||
public Metadata getTaskMetadata(long taskId) {
|
||||
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(
|
||||
ProducteevTask.ID, ProducteevTask.DASHBOARD_ID).where(
|
||||
MetadataCriteria.byTaskAndwithKey(taskId, ProducteevTask.METADATA_KEY)));
|
||||
try {
|
||||
if(cursor.getCount() == 0)
|
||||
return null;
|
||||
cursor.moveToFirst();
|
||||
return new Metadata(cursor);
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads task notes out of a task
|
||||
*/
|
||||
public TodorooCursor<Metadata> getTaskNotesCursor(long taskId) {
|
||||
TodorooCursor<Metadata> cursor = metadataDao.query(Query.select(Metadata.PROPERTIES).
|
||||
where(MetadataCriteria.byTaskAndwithKey(taskId, ProducteevNote.METADATA_KEY)));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
// --- list methods
|
||||
|
||||
private final Map<Long, String> dashboardCache =
|
||||
Collections.synchronizedMap(new SoftHashMap<Long, String>());
|
||||
|
||||
/**
|
||||
* Get dashboard name by dashboard id
|
||||
* @param dashboardId
|
||||
* @return null if no dashboard by this id exists, otherwise dashboard name
|
||||
*/
|
||||
public String getDashboardName(long dashboardId) {
|
||||
if(dashboardCache.containsKey(dashboardId))
|
||||
return dashboardCache.get(dashboardId);
|
||||
|
||||
TodorooCursor<ProducteevDashboard> cursor = prodDashboardDao.query(Query.select(
|
||||
ProducteevDashboard.NAME).where(ProducteevDashboard.ID.eq(dashboardId)));
|
||||
try {
|
||||
if(cursor.getCount() == 0) {
|
||||
dashboardCache.put(dashboardId, null);
|
||||
return null;
|
||||
}
|
||||
cursor.moveToFirst();
|
||||
String name = cursor.get(ProducteevDashboard.NAME);
|
||||
dashboardCache.put(dashboardId, name);
|
||||
return name;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,76 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Todoroo Inc
|
||||
* All Rights Reserved
|
||||
* http://www.todoroo.com
|
||||
*/
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import com.todoroo.andlib.data.AbstractDatabase;
|
||||
import com.todoroo.andlib.data.GenericDao;
|
||||
import com.todoroo.andlib.data.Table;
|
||||
|
||||
/**
|
||||
* Database wrapper
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class ProducteevDatabase extends AbstractDatabase {
|
||||
|
||||
// --- constants
|
||||
|
||||
/**
|
||||
* Database version number. This variable must be updated when database
|
||||
* tables are updated, as it determines whether a database needs updating.
|
||||
*/
|
||||
public static final int VERSION = 1;
|
||||
|
||||
/**
|
||||
* Database name (must be unique)
|
||||
*/
|
||||
private static final String NAME = "producteev";
|
||||
|
||||
/**
|
||||
* List of table/ If you're adding a new table, add it to this list and
|
||||
* also make sure that our SQLite helper does the right thing.
|
||||
*/
|
||||
public static final Table[] TABLES = new Table[] {
|
||||
ProducteevDashboard.TABLE,
|
||||
};
|
||||
|
||||
// --- implementation
|
||||
|
||||
private final GenericDao<ProducteevDashboard> dao = new GenericDao<ProducteevDashboard>(ProducteevDashboard.class, this);
|
||||
|
||||
@Override
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table[] getTables() {
|
||||
return TABLES;
|
||||
}
|
||||
|
||||
public GenericDao<ProducteevDashboard> getDao() {
|
||||
return dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreateTables() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onUpgrade(int oldVersion, int newVersion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009, Todoroo Inc
|
||||
* All Rights Reserved
|
||||
* http://www.todoroo.com
|
||||
*/
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import com.todoroo.andlib.data.AbstractDatabase;
|
||||
import com.todoroo.andlib.data.GenericDao;
|
||||
import com.todoroo.andlib.data.Table;
|
||||
|
||||
/**
|
||||
* Database wrapper
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class ProducteevDatabase extends AbstractDatabase {
|
||||
|
||||
// --- constants
|
||||
|
||||
/**
|
||||
* Database version number. This variable must be updated when database
|
||||
* tables are updated, as it determines whether a database needs updating.
|
||||
*/
|
||||
public static final int VERSION = 1;
|
||||
|
||||
/**
|
||||
* Database name (must be unique)
|
||||
*/
|
||||
private static final String NAME = "producteev";
|
||||
|
||||
/**
|
||||
* List of table/ If you're adding a new table, add it to this list and
|
||||
* also make sure that our SQLite helper does the right thing.
|
||||
*/
|
||||
public static final Table[] TABLES = new Table[] {
|
||||
ProducteevDashboard.TABLE,
|
||||
};
|
||||
|
||||
// --- implementation
|
||||
|
||||
private final GenericDao<ProducteevDashboard> dao = new GenericDao<ProducteevDashboard>(ProducteevDashboard.class, this);
|
||||
|
||||
@Override
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Table[] getTables() {
|
||||
return TABLES;
|
||||
}
|
||||
|
||||
public GenericDao<ProducteevDashboard> getDao() {
|
||||
return dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreateTables() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onUpgrade(int oldVersion, int newVersion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,24 @@
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
|
||||
/**
|
||||
* Metadata entries for a Producteev Task
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class ProducteevTask {
|
||||
|
||||
/** metadata key */
|
||||
public static final String METADATA_KEY = "producteev"; //$NON-NLS-1$
|
||||
|
||||
/** task id in producteev */
|
||||
public static final LongProperty ID = new LongProperty(Metadata.TABLE,
|
||||
Metadata.VALUE1.name);
|
||||
|
||||
/** dashboard id */
|
||||
public static final LongProperty DASHBOARD_ID = new LongProperty(Metadata.TABLE,
|
||||
Metadata.VALUE2.name);
|
||||
|
||||
}
|
||||
package com.todoroo.astrid.producteev.sync;
|
||||
|
||||
import com.todoroo.andlib.data.Property.LongProperty;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
|
||||
/**
|
||||
* Metadata entries for a Producteev Task
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class ProducteevTask {
|
||||
|
||||
/** metadata key */
|
||||
public static final String METADATA_KEY = "producteev"; //$NON-NLS-1$
|
||||
|
||||
/** task id in producteev */
|
||||
public static final LongProperty ID = new LongProperty(Metadata.TABLE,
|
||||
Metadata.VALUE1.name);
|
||||
|
||||
/** dashboard id */
|
||||
public static final LongProperty DASHBOARD_ID = new LongProperty(Metadata.TABLE,
|
||||
Metadata.VALUE2.name);
|
||||
|
||||
}
|
||||
|
@ -1,149 +1,149 @@
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dashboard
|
||||
*
|
||||
* Copyright (c) 2009 Tim Su
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.todoroo.astrid.reminders;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import android.app.TimePickerDialog;
|
||||
import android.app.TimePickerDialog.OnTimeSetListener;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.sql.QueryTemplate;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.activity.TaskListActivity;
|
||||
import com.todoroo.astrid.api.Filter;
|
||||
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
|
||||
import com.todoroo.astrid.utility.Preferences;
|
||||
|
||||
/**
|
||||
* This activity is launched when a user opens up a notification from the
|
||||
* tray. It launches the appropriate activity based on the passed in parameters.
|
||||
*
|
||||
* @author timsu
|
||||
*
|
||||
*/
|
||||
public class NotificationActivity extends TaskListActivity implements OnTimeSetListener {
|
||||
|
||||
// --- constants
|
||||
|
||||
/** task id from notification */
|
||||
public static final String TOKEN_ID = "id"; //$NON-NLS-1$
|
||||
|
||||
// --- implementation
|
||||
|
||||
private long taskId;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
populateFilter(getIntent());
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
displayNotificationPopup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
populateFilter(intent);
|
||||
super.onNewIntent(intent);
|
||||
}
|
||||
|
||||
private void populateFilter(Intent intent) {
|
||||
taskId = intent.getLongExtra(TOKEN_ID, -1);
|
||||
if(taskId == -1)
|
||||
return;
|
||||
|
||||
Filter itemFilter = new Filter(getString(R.string.rmd_NoA_filter),
|
||||
getString(R.string.rmd_NoA_filter),
|
||||
new QueryTemplate().where(TaskCriteria.byId(taskId)),
|
||||
null);
|
||||
intent.putExtra(TaskListActivity.TOKEN_FILTER, itemFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the UI for this activity
|
||||
*/
|
||||
private void displayNotificationPopup() {
|
||||
// hide quick add
|
||||
findViewById(R.id.taskListFooter).setVisibility(View.GONE);
|
||||
|
||||
// instantiate reminder window
|
||||
ViewGroup parent = (ViewGroup) findViewById(R.id.taskListParent);
|
||||
getLayoutInflater().inflate(R.layout.notification_control, parent, true);
|
||||
|
||||
String reminder = Notifications.getRandomReminder(getResources().getStringArray(R.array.reminder_responses));
|
||||
|
||||
if(Preferences.getBoolean(R.string.p_rmd_nagging, true))
|
||||
((TextView)findViewById(R.id.reminderLabel)).setText(reminder);
|
||||
else {
|
||||
findViewById(R.id.reminderLabel).setVisibility(View.GONE);
|
||||
findViewById(R.id.astridIcon).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// set up listeners
|
||||
((Button)findViewById(R.id.goAway)).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
((Button)findViewById(R.id.snooze)).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
snooze();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Snooze and re-trigger this alarm
|
||||
*/
|
||||
private void snooze() {
|
||||
Date now = new Date();
|
||||
now.setHours(now.getHours() + 1);
|
||||
int hour = now.getHours();
|
||||
int minute = now.getMinutes();
|
||||
TimePickerDialog timePicker = new TimePickerDialog(this, this,
|
||||
hour, minute, DateUtilities.is24HourFormat(this));
|
||||
timePicker.show();
|
||||
}
|
||||
|
||||
/** snooze timer set */
|
||||
@Override
|
||||
public void onTimeSet(TimePicker picker, int hours, int minutes) {
|
||||
Date alarmTime = new Date();
|
||||
alarmTime.setHours(hours);
|
||||
alarmTime.setMinutes(minutes);
|
||||
if(alarmTime.getTime() < DateUtilities.now())
|
||||
alarmTime.setDate(alarmTime.getDate() + 1);
|
||||
ReminderService.getInstance().scheduleSnoozeAlarm(taskId, alarmTime.getTime());
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dashboard
|
||||
*
|
||||
* Copyright (c) 2009 Tim Su
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.todoroo.astrid.reminders;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import android.app.TimePickerDialog;
|
||||
import android.app.TimePickerDialog.OnTimeSetListener;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.sql.QueryTemplate;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.activity.TaskListActivity;
|
||||
import com.todoroo.astrid.api.Filter;
|
||||
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
|
||||
import com.todoroo.astrid.utility.Preferences;
|
||||
|
||||
/**
|
||||
* This activity is launched when a user opens up a notification from the
|
||||
* tray. It launches the appropriate activity based on the passed in parameters.
|
||||
*
|
||||
* @author timsu
|
||||
*
|
||||
*/
|
||||
public class NotificationActivity extends TaskListActivity implements OnTimeSetListener {
|
||||
|
||||
// --- constants
|
||||
|
||||
/** task id from notification */
|
||||
public static final String TOKEN_ID = "id"; //$NON-NLS-1$
|
||||
|
||||
// --- implementation
|
||||
|
||||
private long taskId;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
populateFilter(getIntent());
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
displayNotificationPopup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
populateFilter(intent);
|
||||
super.onNewIntent(intent);
|
||||
}
|
||||
|
||||
private void populateFilter(Intent intent) {
|
||||
taskId = intent.getLongExtra(TOKEN_ID, -1);
|
||||
if(taskId == -1)
|
||||
return;
|
||||
|
||||
Filter itemFilter = new Filter(getString(R.string.rmd_NoA_filter),
|
||||
getString(R.string.rmd_NoA_filter),
|
||||
new QueryTemplate().where(TaskCriteria.byId(taskId)),
|
||||
null);
|
||||
intent.putExtra(TaskListActivity.TOKEN_FILTER, itemFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the UI for this activity
|
||||
*/
|
||||
private void displayNotificationPopup() {
|
||||
// hide quick add
|
||||
findViewById(R.id.taskListFooter).setVisibility(View.GONE);
|
||||
|
||||
// instantiate reminder window
|
||||
ViewGroup parent = (ViewGroup) findViewById(R.id.taskListParent);
|
||||
getLayoutInflater().inflate(R.layout.notification_control, parent, true);
|
||||
|
||||
String reminder = Notifications.getRandomReminder(getResources().getStringArray(R.array.reminder_responses));
|
||||
|
||||
if(Preferences.getBoolean(R.string.p_rmd_nagging, true))
|
||||
((TextView)findViewById(R.id.reminderLabel)).setText(reminder);
|
||||
else {
|
||||
findViewById(R.id.reminderLabel).setVisibility(View.GONE);
|
||||
findViewById(R.id.astridIcon).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// set up listeners
|
||||
((Button)findViewById(R.id.goAway)).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
((Button)findViewById(R.id.snooze)).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
snooze();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Snooze and re-trigger this alarm
|
||||
*/
|
||||
private void snooze() {
|
||||
Date now = new Date();
|
||||
now.setHours(now.getHours() + 1);
|
||||
int hour = now.getHours();
|
||||
int minute = now.getMinutes();
|
||||
TimePickerDialog timePicker = new TimePickerDialog(this, this,
|
||||
hour, minute, DateUtilities.is24HourFormat(this));
|
||||
timePicker.show();
|
||||
}
|
||||
|
||||
/** snooze timer set */
|
||||
@Override
|
||||
public void onTimeSet(TimePicker picker, int hours, int minutes) {
|
||||
Date alarmTime = new Date();
|
||||
alarmTime.setHours(hours);
|
||||
alarmTime.setMinutes(minutes);
|
||||
if(alarmTime.getTime() < DateUtilities.now())
|
||||
alarmTime.setDate(alarmTime.getDate() + 1);
|
||||
ReminderService.getInstance().scheduleSnoozeAlarm(taskId, alarmTime.getTime());
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,128 +1,128 @@
|
||||
package com.todoroo.astrid.rmilk;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.rmilk.sync.RTMSyncProvider;
|
||||
import com.todoroo.astrid.utility.Preferences;
|
||||
|
||||
/**
|
||||
* SynchronizationService is the service that performs Astrid's background
|
||||
* synchronization with online task managers. Starting this service
|
||||
* schedules a repeating alarm which handles the synchronization
|
||||
*
|
||||
* @author Tim Su
|
||||
*
|
||||
*/
|
||||
public class MilkBackgroundService extends Service {
|
||||
|
||||
/** Minimum time before an auto-sync */
|
||||
private static final long AUTO_SYNC_MIN_OFFSET = 5*60*1000L;
|
||||
|
||||
/** alarm identifier */
|
||||
private static final String SYNC_ACTION = "sync"; //$NON-NLS-1$
|
||||
|
||||
// --- BroadcastReceiver abstract methods
|
||||
|
||||
/** Receive the alarm - start the synchronize service! */
|
||||
@Override
|
||||
public void onStart(Intent intent, int startId) {
|
||||
if(SYNC_ACTION.equals(intent.getAction()))
|
||||
startSynchronization(this);
|
||||
}
|
||||
|
||||
/** Start the actual synchronization */
|
||||
private void startSynchronization(Context context) {
|
||||
if(context == null || context.getResources() == null)
|
||||
return;
|
||||
|
||||
ContextManager.setContext(context);
|
||||
|
||||
if(MilkUtilities.isOngoing())
|
||||
return;
|
||||
|
||||
new RTMSyncProvider().synchronize(context);
|
||||
}
|
||||
|
||||
// --- alarm management
|
||||
|
||||
/**
|
||||
* Schedules repeating alarm for auto-synchronization
|
||||
*/
|
||||
public static void scheduleService() {
|
||||
int syncFrequencySeconds = Preferences.getIntegerFromString(
|
||||
R.string.rmilk_MPr_interval_key, -1);
|
||||
Context context = ContextManager.getContext();
|
||||
if(syncFrequencySeconds <= 0) {
|
||||
unscheduleService(context);
|
||||
return;
|
||||
}
|
||||
|
||||
// figure out synchronization frequency
|
||||
long interval = 1000L * syncFrequencySeconds;
|
||||
long offset = computeNextSyncOffset(interval);
|
||||
|
||||
// give a little padding
|
||||
offset = Math.max(offset, AUTO_SYNC_MIN_OFFSET);
|
||||
|
||||
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
|
||||
createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
Log.i("Astrid", "Autosync set for " + offset / 1000 //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " seconds repeating every " + syncFrequencySeconds); //$NON-NLS-1$
|
||||
|
||||
// cancel all existing
|
||||
am.cancel(pendingIntent);
|
||||
|
||||
// schedule new
|
||||
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + offset,
|
||||
interval, pendingIntent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes repeating alarm for auto-synchronization
|
||||
*/
|
||||
private static void unscheduleService(Context context) {
|
||||
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
|
||||
createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
am.cancel(pendingIntent);
|
||||
}
|
||||
|
||||
/** Create the alarm intent */
|
||||
private static Intent createAlarmIntent(Context context) {
|
||||
Intent intent = new Intent(context, MilkBackgroundService.class);
|
||||
intent.setAction(SYNC_ACTION);
|
||||
return intent;
|
||||
}
|
||||
|
||||
// --- utility methods
|
||||
|
||||
|
||||
private static long computeNextSyncOffset(long interval) {
|
||||
// figure out last synchronize time
|
||||
long lastSyncDate = MilkUtilities.getLastSyncDate();
|
||||
|
||||
// if user never synchronized, give them a full offset period before bg sync
|
||||
if(lastSyncDate != 0)
|
||||
return Math.max(0, lastSyncDate + interval - DateUtilities.now());
|
||||
else
|
||||
return interval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
package com.todoroo.astrid.rmilk;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.rmilk.sync.RTMSyncProvider;
|
||||
import com.todoroo.astrid.utility.Preferences;
|
||||
|
||||
/**
|
||||
* SynchronizationService is the service that performs Astrid's background
|
||||
* synchronization with online task managers. Starting this service
|
||||
* schedules a repeating alarm which handles the synchronization
|
||||
*
|
||||
* @author Tim Su
|
||||
*
|
||||
*/
|
||||
public class MilkBackgroundService extends Service {
|
||||
|
||||
/** Minimum time before an auto-sync */
|
||||
private static final long AUTO_SYNC_MIN_OFFSET = 5*60*1000L;
|
||||
|
||||
/** alarm identifier */
|
||||
private static final String SYNC_ACTION = "sync"; //$NON-NLS-1$
|
||||
|
||||
// --- BroadcastReceiver abstract methods
|
||||
|
||||
/** Receive the alarm - start the synchronize service! */
|
||||
@Override
|
||||
public void onStart(Intent intent, int startId) {
|
||||
if(SYNC_ACTION.equals(intent.getAction()))
|
||||
startSynchronization(this);
|
||||
}
|
||||
|
||||
/** Start the actual synchronization */
|
||||
private void startSynchronization(Context context) {
|
||||
if(context == null || context.getResources() == null)
|
||||
return;
|
||||
|
||||
ContextManager.setContext(context);
|
||||
|
||||
if(MilkUtilities.isOngoing())
|
||||
return;
|
||||
|
||||
new RTMSyncProvider().synchronize(context);
|
||||
}
|
||||
|
||||
// --- alarm management
|
||||
|
||||
/**
|
||||
* Schedules repeating alarm for auto-synchronization
|
||||
*/
|
||||
public static void scheduleService() {
|
||||
int syncFrequencySeconds = Preferences.getIntegerFromString(
|
||||
R.string.rmilk_MPr_interval_key, -1);
|
||||
Context context = ContextManager.getContext();
|
||||
if(syncFrequencySeconds <= 0) {
|
||||
unscheduleService(context);
|
||||
return;
|
||||
}
|
||||
|
||||
// figure out synchronization frequency
|
||||
long interval = 1000L * syncFrequencySeconds;
|
||||
long offset = computeNextSyncOffset(interval);
|
||||
|
||||
// give a little padding
|
||||
offset = Math.max(offset, AUTO_SYNC_MIN_OFFSET);
|
||||
|
||||
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
|
||||
createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
Log.i("Astrid", "Autosync set for " + offset / 1000 //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " seconds repeating every " + syncFrequencySeconds); //$NON-NLS-1$
|
||||
|
||||
// cancel all existing
|
||||
am.cancel(pendingIntent);
|
||||
|
||||
// schedule new
|
||||
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + offset,
|
||||
interval, pendingIntent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes repeating alarm for auto-synchronization
|
||||
*/
|
||||
private static void unscheduleService(Context context) {
|
||||
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(context, 0,
|
||||
createAlarmIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
am.cancel(pendingIntent);
|
||||
}
|
||||
|
||||
/** Create the alarm intent */
|
||||
private static Intent createAlarmIntent(Context context) {
|
||||
Intent intent = new Intent(context, MilkBackgroundService.class);
|
||||
intent.setAction(SYNC_ACTION);
|
||||
return intent;
|
||||
}
|
||||
|
||||
// --- utility methods
|
||||
|
||||
|
||||
private static long computeNextSyncOffset(long interval) {
|
||||
// figure out last synchronize time
|
||||
long lastSyncDate = MilkUtilities.getLastSyncDate();
|
||||
|
||||
// if user never synchronized, give them a full offset period before bg sync
|
||||
if(lastSyncDate != 0)
|
||||
return Math.max(0, lastSyncDate + interval - DateUtilities.now());
|
||||
else
|
||||
return interval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,106 +1,106 @@
|
||||
/*
|
||||
* Copyright 2007, MetaDimensional Technologies Inc.
|
||||
*
|
||||
*
|
||||
* This file is part of the RememberTheMilk Java API.
|
||||
*
|
||||
* The RememberTheMilk Java API is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The RememberTheMilk Java API is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.todoroo.astrid.rmilk.api.data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.EntityReference;
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Represents a single task note.
|
||||
*
|
||||
* @author Edouard Mercier
|
||||
* @since 2008.04.22
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class RtmTaskNote
|
||||
extends RtmData
|
||||
{
|
||||
|
||||
private final String id;
|
||||
|
||||
private final Date created;
|
||||
|
||||
private final Date modified;
|
||||
|
||||
private final String title;
|
||||
|
||||
private String text;
|
||||
|
||||
public RtmTaskNote(Element element)
|
||||
{
|
||||
id = element.getAttribute("id");
|
||||
created = parseDate(element.getAttribute("created"));
|
||||
modified = parseDate(element.getAttribute("modified"));
|
||||
title = element.getAttribute("title");
|
||||
|
||||
// The note text itself might be split across multiple children of the
|
||||
// note element, so get all of the children.
|
||||
for (int i=0; i < element.getChildNodes().getLength(); i++) {
|
||||
Object innerNote = element.getChildNodes().item(i);
|
||||
|
||||
if(innerNote instanceof EntityReference) // this node is empty
|
||||
continue;
|
||||
|
||||
if(!(innerNote instanceof Text)) {
|
||||
Log.w("rtm-note", "Expected text type, got " + innerNote.getClass());
|
||||
continue;
|
||||
}
|
||||
|
||||
Text innerText = (Text) innerNote;
|
||||
|
||||
if (text == null)
|
||||
text = innerText.getData();
|
||||
else
|
||||
text = text.concat(innerText.getData());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public Date getCreated()
|
||||
{
|
||||
return created;
|
||||
}
|
||||
|
||||
public Date getModified()
|
||||
{
|
||||
return modified;
|
||||
}
|
||||
|
||||
public String getTitle()
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getText()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2007, MetaDimensional Technologies Inc.
|
||||
*
|
||||
*
|
||||
* This file is part of the RememberTheMilk Java API.
|
||||
*
|
||||
* The RememberTheMilk Java API is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* The RememberTheMilk Java API is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.todoroo.astrid.rmilk.api.data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.EntityReference;
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Represents a single task note.
|
||||
*
|
||||
* @author Edouard Mercier
|
||||
* @since 2008.04.22
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class RtmTaskNote
|
||||
extends RtmData
|
||||
{
|
||||
|
||||
private final String id;
|
||||
|
||||
private final Date created;
|
||||
|
||||
private final Date modified;
|
||||
|
||||
private final String title;
|
||||
|
||||
private String text;
|
||||
|
||||
public RtmTaskNote(Element element)
|
||||
{
|
||||
id = element.getAttribute("id");
|
||||
created = parseDate(element.getAttribute("created"));
|
||||
modified = parseDate(element.getAttribute("modified"));
|
||||
title = element.getAttribute("title");
|
||||
|
||||
// The note text itself might be split across multiple children of the
|
||||
// note element, so get all of the children.
|
||||
for (int i=0; i < element.getChildNodes().getLength(); i++) {
|
||||
Object innerNote = element.getChildNodes().item(i);
|
||||
|
||||
if(innerNote instanceof EntityReference) // this node is empty
|
||||
continue;
|
||||
|
||||
if(!(innerNote instanceof Text)) {
|
||||
Log.w("rtm-note", "Expected text type, got " + innerNote.getClass());
|
||||
continue;
|
||||
}
|
||||
|
||||
Text innerText = (Text) innerNote;
|
||||
|
||||
if (text == null)
|
||||
text = innerText.getData();
|
||||
else
|
||||
text = text.concat(innerText.getData());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public Date getCreated()
|
||||
{
|
||||
return created;
|
||||
}
|
||||
|
||||
public Date getModified()
|
||||
{
|
||||
return modified;
|
||||
}
|
||||
|
||||
public String getTitle()
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getText()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,50 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@drawable/background_gradient">
|
||||
|
||||
<!-- =================================================== tab: installed == -->
|
||||
|
||||
<FrameLayout android:id="@+id/tab_installed"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<TextView android:id="@+id/empty_installed"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/TEA_no_addons"
|
||||
style="@style/TextAppearance.TLA_NoItems" />
|
||||
|
||||
<ListView android:id="@+id/installed"
|
||||
android:paddingRight="8dip"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<!-- =================================================== tab: available == -->
|
||||
|
||||
<FrameLayout android:id="@+id/tab_available"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<TextView android:id="@+id/empty_available"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/TEA_no_addons"
|
||||
style="@style/TextAppearance.TLA_NoItems" />
|
||||
|
||||
<ListView android:id="@+id/available"
|
||||
android:paddingRight="8dip"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@drawable/background_gradient">
|
||||
|
||||
<!-- =================================================== tab: installed == -->
|
||||
|
||||
<FrameLayout android:id="@+id/tab_installed"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<TextView android:id="@+id/empty_installed"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/TEA_no_addons"
|
||||
style="@style/TextAppearance.TLA_NoItems" />
|
||||
|
||||
<ListView android:id="@+id/installed"
|
||||
android:paddingRight="8dip"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<!-- =================================================== tab: available == -->
|
||||
|
||||
<FrameLayout android:id="@+id/tab_available"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<TextView android:id="@+id/empty_available"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/TEA_no_addons"
|
||||
style="@style/TextAppearance.TLA_NoItems" />
|
||||
|
||||
<ListView android:id="@+id/available"
|
||||
android:paddingRight="8dip"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
@ -1,88 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:background="@android:drawable/list_selector_background"
|
||||
android:paddingTop="4dip"
|
||||
android:paddingBottom="4dip"
|
||||
android:paddingLeft="4dip"
|
||||
android:paddingRight="4dip">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5dip"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- icon -->
|
||||
<ImageView android:id="@+id/icon"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:gravity="center"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<!-- free -->
|
||||
<TextView android:id="@+id/free"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textSize="10sp"
|
||||
android:textColor="#00ff00"
|
||||
android:text="@string/AOA_free" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="100"
|
||||
android:paddingLeft="8dip"
|
||||
android:paddingRight="3dip"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- add-on name -->
|
||||
<TextView android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:singleLine="true"
|
||||
style="@style/TextAppearance.TAd_ItemTitle"/>
|
||||
|
||||
<!-- description -->
|
||||
<TextView android:id="@+id/description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/title"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:singleLine="false"
|
||||
android:textSize="11sp"
|
||||
style="@style/TextAppearance.TAd_ItemDetails"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- buttons -->
|
||||
|
||||
<ImageButton android:id="@+id/button_web"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ImageButton android:id="@+id/button_market"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ImageView android:id="@+id/check"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="center"
|
||||
android:layout_gravity="center"
|
||||
android:src="@android:drawable/checkbox_on_background"/>
|
||||
|
||||
</LinearLayout>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:background="@android:drawable/list_selector_background"
|
||||
android:paddingTop="4dip"
|
||||
android:paddingBottom="4dip"
|
||||
android:paddingLeft="4dip"
|
||||
android:paddingRight="4dip">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5dip"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- icon -->
|
||||
<ImageView android:id="@+id/icon"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:gravity="center"
|
||||
android:scaleType="fitCenter"/>
|
||||
|
||||
<!-- free -->
|
||||
<TextView android:id="@+id/free"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textSize="10sp"
|
||||
android:textColor="#00ff00"
|
||||
android:text="@string/AOA_free" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="100"
|
||||
android:paddingLeft="8dip"
|
||||
android:paddingRight="3dip"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- add-on name -->
|
||||
<TextView android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:singleLine="true"
|
||||
style="@style/TextAppearance.TAd_ItemTitle"/>
|
||||
|
||||
<!-- description -->
|
||||
<TextView android:id="@+id/description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/title"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:singleLine="false"
|
||||
android:textSize="11sp"
|
||||
style="@style/TextAppearance.TAd_ItemDetails"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- buttons -->
|
||||
|
||||
<ImageButton android:id="@+id/button_web"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ImageButton android:id="@+id/button_market"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="fitCenter"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ImageView android:id="@+id/check"
|
||||
android:layout_width="48dip"
|
||||
android:layout_height="48dip"
|
||||
android:scaleType="center"
|
||||
android:layout_gravity="center"
|
||||
android:src="@android:drawable/checkbox_on_background"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1,304 +1,304 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@drawable/background_gradient">
|
||||
|
||||
<!-- ======================================================= tab: basic == -->
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/tab_basic"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<LinearLayout
|
||||
android:id="@+id/event"
|
||||
android:paddingRight="8dip"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<!-- title -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_title_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<EditText
|
||||
android:id="@+id/title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/TEA_title_hint"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences" />
|
||||
|
||||
<!-- importance -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_importance_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<LinearLayout
|
||||
android:id="@+id/importance_container"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
</LinearLayout>
|
||||
|
||||
<!-- urgency -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_urgency_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<Spinner
|
||||
android:id="@+id/urgency"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- tags -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_tags_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<LinearLayout
|
||||
android:id="@+id/tags_container"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- separator -->
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dip"
|
||||
android:padding="5dip"
|
||||
android:background="@android:drawable/divider_horizontal_dark" />
|
||||
|
||||
<!-- notes -->
|
||||
<TextView
|
||||
android:paddingTop="5dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_note_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<EditText
|
||||
android:id="@+id/notes"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:scrollbars="vertical"
|
||||
android:gravity="top"
|
||||
android:hint="@string/TEA_notes_hint"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences"
|
||||
android:singleLine="false" />
|
||||
|
||||
<!-- buttons -->
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dip"
|
||||
android:padding="5dip"
|
||||
android:background="@drawable/edit_header"
|
||||
android:baselineAligned="false">
|
||||
<ImageButton
|
||||
android:id="@+id/save_basic"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_save" />
|
||||
<ImageButton
|
||||
android:id="@+id/discard_basic"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_stop" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<!-- ======================================================= tab: extra == -->
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/tab_extra"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<LinearLayout
|
||||
android:paddingRight="8dip"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<!-- reminders -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_reminder_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<CheckBox
|
||||
android:id="@+id/reminder_due"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_reminder_due" />
|
||||
<CheckBox
|
||||
android:id="@+id/reminder_overdue"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_reminder_overdue" />
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<CheckBox
|
||||
android:id="@+id/reminder_random"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_reminder_random" />
|
||||
<Spinner
|
||||
android:id="@+id/reminder_random_interval"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- reminder mode -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_reminder_alarm_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<Spinner
|
||||
android:id="@+id/reminder_alarm"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- separator -->
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dip"
|
||||
android:padding="5dip"
|
||||
android:background="@android:drawable/divider_horizontal_dark" />
|
||||
|
||||
<!-- hide until -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_hideUntil_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<Spinner
|
||||
android:id="@+id/hideUntil"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- add-ons -->
|
||||
<LinearLayout android:id="@+id/tab_extra_addons"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<!-- buttons -->
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dip"
|
||||
android:padding="5dip"
|
||||
android:background="@drawable/edit_header"
|
||||
android:baselineAligned="false">
|
||||
<ImageButton
|
||||
android:id="@+id/save_extra"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_save" />
|
||||
<ImageButton
|
||||
android:id="@+id/discard_extra"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_stop" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<!-- ===================================================== tab: add-ons == -->
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/tab_addons"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="100">
|
||||
|
||||
<!-- add-ons -->
|
||||
<LinearLayout android:id="@+id/tab_addons_addons"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<LinearLayout android:id="@+id/addons_empty"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="100"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="20dip"
|
||||
android:src="@drawable/icon_pp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_no_addons"
|
||||
android:padding="10dip"
|
||||
android:gravity="center"
|
||||
style="@style/TextAppearance.TLA_NoItems" />
|
||||
|
||||
<Button android:id="@+id/addons_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dip"
|
||||
android:text="@string/TEA_addons_button" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginTop="10dip"
|
||||
android:padding="5dip"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/edit_header"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/save_addons"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_save" />
|
||||
<ImageButton
|
||||
android:id="@+id/discard_addons"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_stop" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@drawable/background_gradient">
|
||||
|
||||
<!-- ======================================================= tab: basic == -->
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/tab_basic"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<LinearLayout
|
||||
android:id="@+id/event"
|
||||
android:paddingRight="8dip"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<!-- title -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_title_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<EditText
|
||||
android:id="@+id/title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/TEA_title_hint"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences" />
|
||||
|
||||
<!-- importance -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_importance_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<LinearLayout
|
||||
android:id="@+id/importance_container"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
</LinearLayout>
|
||||
|
||||
<!-- urgency -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_urgency_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<Spinner
|
||||
android:id="@+id/urgency"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- tags -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_tags_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<LinearLayout
|
||||
android:id="@+id/tags_container"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="5dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- separator -->
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dip"
|
||||
android:padding="5dip"
|
||||
android:background="@android:drawable/divider_horizontal_dark" />
|
||||
|
||||
<!-- notes -->
|
||||
<TextView
|
||||
android:paddingTop="5dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_note_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<EditText
|
||||
android:id="@+id/notes"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:scrollbars="vertical"
|
||||
android:gravity="top"
|
||||
android:hint="@string/TEA_notes_hint"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences"
|
||||
android:singleLine="false" />
|
||||
|
||||
<!-- buttons -->
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dip"
|
||||
android:padding="5dip"
|
||||
android:background="@drawable/edit_header"
|
||||
android:baselineAligned="false">
|
||||
<ImageButton
|
||||
android:id="@+id/save_basic"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_save" />
|
||||
<ImageButton
|
||||
android:id="@+id/discard_basic"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_stop" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<!-- ======================================================= tab: extra == -->
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/tab_extra"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<LinearLayout
|
||||
android:paddingRight="8dip"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<!-- reminders -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_reminder_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<CheckBox
|
||||
android:id="@+id/reminder_due"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_reminder_due" />
|
||||
<CheckBox
|
||||
android:id="@+id/reminder_overdue"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_reminder_overdue" />
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<CheckBox
|
||||
android:id="@+id/reminder_random"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_reminder_random" />
|
||||
<Spinner
|
||||
android:id="@+id/reminder_random_interval"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- reminder mode -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_reminder_alarm_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<Spinner
|
||||
android:id="@+id/reminder_alarm"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- separator -->
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dip"
|
||||
android:padding="5dip"
|
||||
android:background="@android:drawable/divider_horizontal_dark" />
|
||||
|
||||
<!-- hide until -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_hideUntil_label"
|
||||
style="@style/TextAppearance.GEN_EditLabel" />
|
||||
<Spinner
|
||||
android:id="@+id/hideUntil"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<!-- add-ons -->
|
||||
<LinearLayout android:id="@+id/tab_extra_addons"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<!-- buttons -->
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dip"
|
||||
android:padding="5dip"
|
||||
android:background="@drawable/edit_header"
|
||||
android:baselineAligned="false">
|
||||
<ImageButton
|
||||
android:id="@+id/save_extra"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_save" />
|
||||
<ImageButton
|
||||
android:id="@+id/discard_extra"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_stop" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<!-- ===================================================== tab: add-ons == -->
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/tab_addons"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="100">
|
||||
|
||||
<!-- add-ons -->
|
||||
<LinearLayout android:id="@+id/tab_addons_addons"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<LinearLayout android:id="@+id/addons_empty"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="100"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="20dip"
|
||||
android:src="@drawable/icon_pp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/TEA_no_addons"
|
||||
android:padding="10dip"
|
||||
android:gravity="center"
|
||||
style="@style/TextAppearance.TLA_NoItems" />
|
||||
|
||||
<Button android:id="@+id/addons_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dip"
|
||||
android:text="@string/TEA_addons_button" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginTop="10dip"
|
||||
android:padding="5dip"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/edit_header"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/save_addons"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_save" />
|
||||
<ImageButton
|
||||
android:id="@+id/discard_addons"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/tango_stop" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
@ -1,30 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- ====================== Plugin Boilerplate ========================= -->
|
||||
|
||||
<!-- task detail showing Producteev dashboard information -->
|
||||
<string name="producteev_TLA_dashboard">Producteev dashboard: %s</string>
|
||||
|
||||
<!-- ==================================================== Preferences == -->
|
||||
|
||||
<!-- Preferences Title: Producteev -->
|
||||
<string name="producteev_PPr_header">Producteev</string>
|
||||
|
||||
<!-- ================================================ Synchronization == -->
|
||||
|
||||
<!-- title for notification tray when synchronizing -->
|
||||
<string name="producteev_notification_title">Astrid: Producteev</string>
|
||||
|
||||
<!-- Error msg when io exception -->
|
||||
<string name="producteev_ioerror">Connection Error! Check your Internet connection.</string>
|
||||
|
||||
<!-- Prod Login email not specified-->
|
||||
<string name="producteev_MLA_email_empty">E-Mail was not specified!</string>
|
||||
|
||||
<!-- Prod Login password not specified-->
|
||||
<string name="producteev_MLA_password_empty">Password was not specified!</string>
|
||||
|
||||
</resources>
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- See the file "LICENSE" for the full license governing this code. -->
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- ====================== Plugin Boilerplate ========================= -->
|
||||
|
||||
<!-- task detail showing Producteev dashboard information -->
|
||||
<string name="producteev_TLA_dashboard">Producteev dashboard: %s</string>
|
||||
|
||||
<!-- ==================================================== Preferences == -->
|
||||
|
||||
<!-- Preferences Title: Producteev -->
|
||||
<string name="producteev_PPr_header">Producteev</string>
|
||||
|
||||
<!-- ================================================ Synchronization == -->
|
||||
|
||||
<!-- title for notification tray when synchronizing -->
|
||||
<string name="producteev_notification_title">Astrid: Producteev</string>
|
||||
|
||||
<!-- Error msg when io exception -->
|
||||
<string name="producteev_ioerror">Connection Error! Check your Internet connection.</string>
|
||||
|
||||
<!-- Prod Login email not specified-->
|
||||
<string name="producteev_MLA_email_empty">E-Mail was not specified!</string>
|
||||
|
||||
<!-- Prod Login password not specified-->
|
||||
<string name="producteev_MLA_password_empty">Password was not specified!</string>
|
||||
|
||||
</resources>
|
||||
|
||||
|
@ -1,63 +1,63 @@
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dashboard
|
||||
*
|
||||
* Copyright (c) 2009 Tim Su
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.timsu.astrid.activities;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.todoroo.astrid.activity.TaskListActivity;
|
||||
|
||||
/**
|
||||
* Legacy task shortcut, takes users to the updated {@link TaskListActivity}.
|
||||
* This activity is around so users with existing desktop icons will
|
||||
* be able to still launch Astrid.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class TaskList extends Activity {
|
||||
|
||||
// --- implementation
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
launchTaskList(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
launchTaskList(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* intent: ignored for now
|
||||
* @param intent
|
||||
*/
|
||||
private void launchTaskList(Intent intent) {
|
||||
Intent taskListIntent = new Intent(this, TaskListActivity.class);
|
||||
startActivity(taskListIntent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dashboard
|
||||
*
|
||||
* Copyright (c) 2009 Tim Su
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.timsu.astrid.activities;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.todoroo.astrid.activity.TaskListActivity;
|
||||
|
||||
/**
|
||||
* Legacy task shortcut, takes users to the updated {@link TaskListActivity}.
|
||||
* This activity is around so users with existing desktop icons will
|
||||
* be able to still launch Astrid.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
public class TaskList extends Activity {
|
||||
|
||||
// --- implementation
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
launchTaskList(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
launchTaskList(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* intent: ignored for now
|
||||
* @param intent
|
||||
*/
|
||||
private void launchTaskList(Intent intent) {
|
||||
Intent taskListIntent = new Intent(this, TaskListActivity.class);
|
||||
startActivity(taskListIntent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
@ -1,107 +1,107 @@
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dashboard
|
||||
*
|
||||
* Copyright (c) 2009 Tim Su
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.todoroo.astrid.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.sql.QueryTemplate;
|
||||
import com.todoroo.andlib.utility.AndroidUtilities;
|
||||
import com.todoroo.astrid.api.Filter;
|
||||
|
||||
/**
|
||||
* This activity is launched when a user opens up a notification from the
|
||||
* tray. It launches the appropriate activity based on the passed in parameters.
|
||||
*
|
||||
* @author timsu
|
||||
*
|
||||
*/
|
||||
public class ShortcutActivity extends Activity {
|
||||
|
||||
// --- constants
|
||||
|
||||
/** token for passing a {@link Filter}'s title through extras */
|
||||
public static final String TOKEN_FILTER_TITLE = "title"; //$NON-NLS-1$
|
||||
|
||||
/** token for passing a {@link Filter}'s sql through extras */
|
||||
public static final String TOKEN_FILTER_SQL = "sql"; //$NON-NLS-1$
|
||||
|
||||
/** token for passing a {@link Filter}'s values for new tasks through extras */
|
||||
public static final String TOKEN_FILTER_VALUES = "v4nt"; //$NON-NLS-1$
|
||||
|
||||
/** token for passing a {@link Filter}'s values for new tasks through extras (keys) */
|
||||
public static final String TOKEN_FILTER_VALUES_KEYS = "v4ntk"; //$NON-NLS-1$
|
||||
|
||||
/** token for passing a {@link Filter}'s values for new tasks through extras (values) */
|
||||
public static final String TOKEN_FILTER_VALUES_VALUES = "v4ntv"; //$NON-NLS-1$
|
||||
|
||||
// --- implementation
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
launchTaskList(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
launchTaskList(intent);
|
||||
}
|
||||
|
||||
private void launchTaskList(Intent intent) {
|
||||
Bundle extras = intent.getExtras();
|
||||
|
||||
if(extras != null && extras.containsKey(TOKEN_FILTER_SQL)) {
|
||||
// launched from desktop shortcut, must create a fake filter
|
||||
String title = extras.getString(TOKEN_FILTER_TITLE);
|
||||
String sql = extras.getString(TOKEN_FILTER_SQL);
|
||||
ContentValues values = null;
|
||||
if(extras.containsKey(TOKEN_FILTER_VALUES))
|
||||
values = AndroidUtilities.contentValuesFromString(extras.getString(TOKEN_FILTER_VALUES));
|
||||
|
||||
Filter filter = new Filter("", title, new QueryTemplate(), values); //$NON-NLS-1$
|
||||
filter.sqlQuery = sql;
|
||||
|
||||
Intent taskListIntent = new Intent(this, TaskListActivity.class);
|
||||
taskListIntent.putExtra(TaskListActivity.TOKEN_FILTER, filter);
|
||||
startActivity(taskListIntent);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
public static Intent createIntent(Filter filter) {
|
||||
Intent shortcutIntent = new Intent(ContextManager.getContext(),
|
||||
ShortcutActivity.class);
|
||||
shortcutIntent.setAction(Intent.ACTION_VIEW);
|
||||
shortcutIntent.putExtra(ShortcutActivity.TOKEN_FILTER_TITLE, filter.title);
|
||||
shortcutIntent.putExtra(ShortcutActivity.TOKEN_FILTER_SQL, filter.sqlQuery);
|
||||
if(filter.valuesForNewTasks != null) {
|
||||
shortcutIntent.putExtra(ShortcutActivity.TOKEN_FILTER_VALUES,
|
||||
filter.valuesForNewTasks.toString());
|
||||
}
|
||||
return shortcutIntent;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ASTRID: Android's Simple Task Recording Dashboard
|
||||
*
|
||||
* Copyright (c) 2009 Tim Su
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package com.todoroo.astrid.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.sql.QueryTemplate;
|
||||
import com.todoroo.andlib.utility.AndroidUtilities;
|
||||
import com.todoroo.astrid.api.Filter;
|
||||
|
||||
/**
|
||||
* This activity is launched when a user opens up a notification from the
|
||||
* tray. It launches the appropriate activity based on the passed in parameters.
|
||||
*
|
||||
* @author timsu
|
||||
*
|
||||
*/
|
||||
public class ShortcutActivity extends Activity {
|
||||
|
||||
// --- constants
|
||||
|
||||
/** token for passing a {@link Filter}'s title through extras */
|
||||
public static final String TOKEN_FILTER_TITLE = "title"; //$NON-NLS-1$
|
||||
|
||||
/** token for passing a {@link Filter}'s sql through extras */
|
||||
public static final String TOKEN_FILTER_SQL = "sql"; //$NON-NLS-1$
|
||||
|
||||
/** token for passing a {@link Filter}'s values for new tasks through extras */
|
||||
public static final String TOKEN_FILTER_VALUES = "v4nt"; //$NON-NLS-1$
|
||||
|
||||
/** token for passing a {@link Filter}'s values for new tasks through extras (keys) */
|
||||
public static final String TOKEN_FILTER_VALUES_KEYS = "v4ntk"; //$NON-NLS-1$
|
||||
|
||||
/** token for passing a {@link Filter}'s values for new tasks through extras (values) */
|
||||
public static final String TOKEN_FILTER_VALUES_VALUES = "v4ntv"; //$NON-NLS-1$
|
||||
|
||||
// --- implementation
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
launchTaskList(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
launchTaskList(intent);
|
||||
}
|
||||
|
||||
private void launchTaskList(Intent intent) {
|
||||
Bundle extras = intent.getExtras();
|
||||
|
||||
if(extras != null && extras.containsKey(TOKEN_FILTER_SQL)) {
|
||||
// launched from desktop shortcut, must create a fake filter
|
||||
String title = extras.getString(TOKEN_FILTER_TITLE);
|
||||
String sql = extras.getString(TOKEN_FILTER_SQL);
|
||||
ContentValues values = null;
|
||||
if(extras.containsKey(TOKEN_FILTER_VALUES))
|
||||
values = AndroidUtilities.contentValuesFromString(extras.getString(TOKEN_FILTER_VALUES));
|
||||
|
||||
Filter filter = new Filter("", title, new QueryTemplate(), values); //$NON-NLS-1$
|
||||
filter.sqlQuery = sql;
|
||||
|
||||
Intent taskListIntent = new Intent(this, TaskListActivity.class);
|
||||
taskListIntent.putExtra(TaskListActivity.TOKEN_FILTER, filter);
|
||||
startActivity(taskListIntent);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
public static Intent createIntent(Filter filter) {
|
||||
Intent shortcutIntent = new Intent(ContextManager.getContext(),
|
||||
ShortcutActivity.class);
|
||||
shortcutIntent.setAction(Intent.ACTION_VIEW);
|
||||
shortcutIntent.putExtra(ShortcutActivity.TOKEN_FILTER_TITLE, filter.title);
|
||||
shortcutIntent.putExtra(ShortcutActivity.TOKEN_FILTER_SQL, filter.sqlQuery);
|
||||
if(filter.valuesForNewTasks != null) {
|
||||
shortcutIntent.putExtra(ShortcutActivity.TOKEN_FILTER_VALUES,
|
||||
filter.valuesForNewTasks.toString());
|
||||
}
|
||||
return shortcutIntent;
|
||||
}
|
||||
}
|
||||
|
@ -1,288 +1,288 @@
|
||||
package com.todoroo.astrid.provider;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.andlib.sql.Criterion;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||
import com.todoroo.astrid.service.TaskService;
|
||||
import com.todoroo.astrid.tags.TagService;
|
||||
import com.todoroo.astrid.tags.TagService.Tag;
|
||||
|
||||
/**
|
||||
* This is the legacy Astrid task provider. While it will continue to be
|
||||
* supported, note that it does not expose all of the information in
|
||||
* Astrid, nor does it support many editing operations.
|
||||
*
|
||||
* See the individual methods for a description of what is returned.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class Astrid2TaskProvider extends ContentProvider {
|
||||
|
||||
static {
|
||||
AstridDependencyInjector.initialize();
|
||||
}
|
||||
|
||||
private static final String TAG = "MessageProvider";
|
||||
|
||||
private static final boolean LOGD = false;
|
||||
|
||||
|
||||
public static final String AUTHORITY = "com.timsu.astrid.tasksprovider";
|
||||
|
||||
public static final Uri CONTENT_URI = Uri.parse("content://com.timsu.astrid.tasksprovider");
|
||||
|
||||
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
|
||||
private static final int MAX_NUMBER_OF_TASKS = 30;
|
||||
|
||||
private final static String NAME = "name";
|
||||
private final static String IMPORTANCE_COLOR = "importance_color";
|
||||
private final static String IDENTIFIER = "identifier";
|
||||
private final static String PREFERRED_DUE_DATE = "preferredDueDate";
|
||||
private final static String DEFINITE_DUE_DATE = "definiteDueDate";
|
||||
private final static String IMPORTANCE = "importance";
|
||||
private final static String ID = "id";
|
||||
|
||||
// fake property for updating that completes a task
|
||||
private final static String COMPLETED = "completed";
|
||||
|
||||
private final static String TAGS_ID = "tags_id";
|
||||
|
||||
static String[] TASK_FIELD_LIST = new String[] { NAME, IMPORTANCE_COLOR, PREFERRED_DUE_DATE, DEFINITE_DUE_DATE,
|
||||
IMPORTANCE, IDENTIFIER, TAGS_ID };
|
||||
|
||||
static String[] TAGS_FIELD_LIST = new String[] { ID, NAME };
|
||||
|
||||
private static final int URI_TASKS = 0;
|
||||
private static final int URI_TAGS = 1;
|
||||
|
||||
private static final String TAG_SEPARATOR = "|";
|
||||
|
||||
@Autowired
|
||||
private TaskService taskService;
|
||||
|
||||
private static Context ctx = null;
|
||||
|
||||
static {
|
||||
URI_MATCHER.addURI(AUTHORITY, "tasks", URI_TASKS);
|
||||
URI_MATCHER.addURI(AUTHORITY, "tags", URI_TAGS);
|
||||
|
||||
AstridDependencyInjector.initialize();
|
||||
}
|
||||
|
||||
public Astrid2TaskProvider() {
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
if (LOGD)
|
||||
Log.d(TAG, "delete");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
ctx = getContext();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: tag id is no longer a real column, so we pass in a UID
|
||||
* generated from the tag string.
|
||||
*
|
||||
* @return two-column cursor: tag id (string) and tag name
|
||||
*/
|
||||
public Cursor getTags() {
|
||||
|
||||
Tag[] tags = TagService.getInstance().getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE);
|
||||
|
||||
MatrixCursor ret = new MatrixCursor(TAGS_FIELD_LIST);
|
||||
|
||||
for (int i = 0; i < tags.length; i++) {
|
||||
Object[] values = new Object[2];
|
||||
values[0] = tagNameToLong(tags[i].tag);
|
||||
values[1] = tags[i].tag;
|
||||
|
||||
ret.addRow(values);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private long tagNameToLong(String tag) {
|
||||
MessageDigest m;
|
||||
try {
|
||||
m = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
m.update(tag.getBytes(), 0, tag.length());
|
||||
return new BigInteger(1, m.digest()).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cursor with the following columns
|
||||
* <ol>
|
||||
* <li>task title, string
|
||||
* <li>task importance color, int android RGB color
|
||||
* <li>task due date (was: preferred due date), long millis since epoch
|
||||
* <li>task due date (was: absolute due date), long millis since epoch
|
||||
* <li>task importance, integer from 0 to 3 (0 => most important)
|
||||
* <li>task id, long
|
||||
* <li>task tags, string tags separated by |
|
||||
* </ol>
|
||||
*
|
||||
* @return cursor as described above
|
||||
*/
|
||||
public Cursor getTasks() {
|
||||
|
||||
MatrixCursor ret = new MatrixCursor(TASK_FIELD_LIST);
|
||||
|
||||
TodorooCursor<Task> cursor = taskService.query(Query.select(Task.ID, Task.TITLE,
|
||||
Task.IMPORTANCE, Task.DUE_DATE).where(Criterion.and(TaskCriteria.isActive(),
|
||||
TaskCriteria.isVisible())).
|
||||
orderBy(TaskService.defaultTaskOrder()).limit(MAX_NUMBER_OF_TASKS));
|
||||
try {
|
||||
int[] importanceColors = Task.getImportanceColors(ctx.getResources());
|
||||
Task task = new Task();
|
||||
for (int i = 0; i < cursor.getCount(); i++) {
|
||||
cursor.moveToNext();
|
||||
task.readFromCursor(cursor);
|
||||
|
||||
StringBuilder taskTags = new StringBuilder();
|
||||
TodorooCursor<Metadata> tagCursor = TagService.getInstance().getTags(task.getId());
|
||||
try {
|
||||
for(tagCursor.moveToFirst(); !tagCursor.isAfterLast(); tagCursor.moveToNext())
|
||||
taskTags.append(tagCursor.get(TagService.TAG)).append(TAG_SEPARATOR);
|
||||
} finally {
|
||||
tagCursor.close();
|
||||
}
|
||||
|
||||
Object[] values = new Object[7];
|
||||
values[0] = task.getValue(Task.TITLE);
|
||||
values[1] = importanceColors[task.getValue(Task.IMPORTANCE)];
|
||||
values[2] = task.getValue(Task.DUE_DATE);
|
||||
values[3] = task.getValue(Task.DUE_DATE);
|
||||
values[4] = task.getValue(Task.IMPORTANCE);
|
||||
values[5] = task.getId();
|
||||
values[6] = taskTags.toString();
|
||||
|
||||
ret.addRow(values);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
|
||||
if (LOGD)
|
||||
Log.d(TAG, "query");
|
||||
|
||||
Cursor cursor;
|
||||
switch (URI_MATCHER.match(uri)) {
|
||||
|
||||
case URI_TASKS:
|
||||
cursor = getTasks();
|
||||
break;
|
||||
|
||||
case URI_TAGS:
|
||||
cursor = getTags();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unrecognized URI:" + uri);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||
|
||||
if (LOGD)
|
||||
Log.d(TAG, "update");
|
||||
|
||||
switch (URI_MATCHER.match(uri)) {
|
||||
|
||||
case URI_TASKS:
|
||||
Task task = new Task();
|
||||
|
||||
// map values
|
||||
if(values.containsKey(NAME))
|
||||
task.setValue(Task.TITLE, values.getAsString(NAME));
|
||||
if(values.containsKey(PREFERRED_DUE_DATE))
|
||||
task.setValue(Task.DUE_DATE, values.getAsLong(PREFERRED_DUE_DATE));
|
||||
if(values.containsKey(DEFINITE_DUE_DATE))
|
||||
task.setValue(Task.DUE_DATE, values.getAsLong(DEFINITE_DUE_DATE));
|
||||
if(values.containsKey(IMPORTANCE))
|
||||
task.setValue(Task.IMPORTANCE, values.getAsInteger(IMPORTANCE));
|
||||
if(values.containsKey(COMPLETED))
|
||||
task.setValue(Task.COMPLETION_DATE,
|
||||
values.getAsBoolean(COMPLETED) ? DateUtilities.now() : 0);
|
||||
|
||||
// map selection criteria
|
||||
String criteria = selection.replace(NAME, Task.TITLE.name).
|
||||
replace(PREFERRED_DUE_DATE, Task.DUE_DATE.name).
|
||||
replace(DEFINITE_DUE_DATE, Task.DUE_DATE.name).
|
||||
replace(IDENTIFIER, Task.ID.name).
|
||||
replace(ID, Task.ID.name).
|
||||
replace(IMPORTANCE, Task.IMPORTANCE.name);
|
||||
|
||||
return taskService.updateBySelection(criteria, selectionArgs, task);
|
||||
|
||||
case URI_TAGS:
|
||||
throw new UnsupportedOperationException("tags updating: not yet");
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unrecognized URI:" + uri);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyDatabaseModification() {
|
||||
|
||||
if (LOGD)
|
||||
Log.d(TAG, "notifyDatabaseModification");
|
||||
|
||||
ctx.getContentResolver().notifyChange(CONTENT_URI, null);
|
||||
}
|
||||
|
||||
}
|
||||
package com.todoroo.astrid.provider;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.andlib.sql.Criterion;
|
||||
import com.todoroo.andlib.sql.Query;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
|
||||
import com.todoroo.astrid.model.Metadata;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||
import com.todoroo.astrid.service.TaskService;
|
||||
import com.todoroo.astrid.tags.TagService;
|
||||
import com.todoroo.astrid.tags.TagService.Tag;
|
||||
|
||||
/**
|
||||
* This is the legacy Astrid task provider. While it will continue to be
|
||||
* supported, note that it does not expose all of the information in
|
||||
* Astrid, nor does it support many editing operations.
|
||||
*
|
||||
* See the individual methods for a description of what is returned.
|
||||
*
|
||||
* @author Tim Su <tim@todoroo.com>
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class Astrid2TaskProvider extends ContentProvider {
|
||||
|
||||
static {
|
||||
AstridDependencyInjector.initialize();
|
||||
}
|
||||
|
||||
private static final String TAG = "MessageProvider";
|
||||
|
||||
private static final boolean LOGD = false;
|
||||
|
||||
|
||||
public static final String AUTHORITY = "com.timsu.astrid.tasksprovider";
|
||||
|
||||
public static final Uri CONTENT_URI = Uri.parse("content://com.timsu.astrid.tasksprovider");
|
||||
|
||||
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
|
||||
private static final int MAX_NUMBER_OF_TASKS = 30;
|
||||
|
||||
private final static String NAME = "name";
|
||||
private final static String IMPORTANCE_COLOR = "importance_color";
|
||||
private final static String IDENTIFIER = "identifier";
|
||||
private final static String PREFERRED_DUE_DATE = "preferredDueDate";
|
||||
private final static String DEFINITE_DUE_DATE = "definiteDueDate";
|
||||
private final static String IMPORTANCE = "importance";
|
||||
private final static String ID = "id";
|
||||
|
||||
// fake property for updating that completes a task
|
||||
private final static String COMPLETED = "completed";
|
||||
|
||||
private final static String TAGS_ID = "tags_id";
|
||||
|
||||
static String[] TASK_FIELD_LIST = new String[] { NAME, IMPORTANCE_COLOR, PREFERRED_DUE_DATE, DEFINITE_DUE_DATE,
|
||||
IMPORTANCE, IDENTIFIER, TAGS_ID };
|
||||
|
||||
static String[] TAGS_FIELD_LIST = new String[] { ID, NAME };
|
||||
|
||||
private static final int URI_TASKS = 0;
|
||||
private static final int URI_TAGS = 1;
|
||||
|
||||
private static final String TAG_SEPARATOR = "|";
|
||||
|
||||
@Autowired
|
||||
private TaskService taskService;
|
||||
|
||||
private static Context ctx = null;
|
||||
|
||||
static {
|
||||
URI_MATCHER.addURI(AUTHORITY, "tasks", URI_TASKS);
|
||||
URI_MATCHER.addURI(AUTHORITY, "tags", URI_TAGS);
|
||||
|
||||
AstridDependencyInjector.initialize();
|
||||
}
|
||||
|
||||
public Astrid2TaskProvider() {
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
if (LOGD)
|
||||
Log.d(TAG, "delete");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
ctx = getContext();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: tag id is no longer a real column, so we pass in a UID
|
||||
* generated from the tag string.
|
||||
*
|
||||
* @return two-column cursor: tag id (string) and tag name
|
||||
*/
|
||||
public Cursor getTags() {
|
||||
|
||||
Tag[] tags = TagService.getInstance().getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE);
|
||||
|
||||
MatrixCursor ret = new MatrixCursor(TAGS_FIELD_LIST);
|
||||
|
||||
for (int i = 0; i < tags.length; i++) {
|
||||
Object[] values = new Object[2];
|
||||
values[0] = tagNameToLong(tags[i].tag);
|
||||
values[1] = tags[i].tag;
|
||||
|
||||
ret.addRow(values);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private long tagNameToLong(String tag) {
|
||||
MessageDigest m;
|
||||
try {
|
||||
m = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
m.update(tag.getBytes(), 0, tag.length());
|
||||
return new BigInteger(1, m.digest()).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cursor with the following columns
|
||||
* <ol>
|
||||
* <li>task title, string
|
||||
* <li>task importance color, int android RGB color
|
||||
* <li>task due date (was: preferred due date), long millis since epoch
|
||||
* <li>task due date (was: absolute due date), long millis since epoch
|
||||
* <li>task importance, integer from 0 to 3 (0 => most important)
|
||||
* <li>task id, long
|
||||
* <li>task tags, string tags separated by |
|
||||
* </ol>
|
||||
*
|
||||
* @return cursor as described above
|
||||
*/
|
||||
public Cursor getTasks() {
|
||||
|
||||
MatrixCursor ret = new MatrixCursor(TASK_FIELD_LIST);
|
||||
|
||||
TodorooCursor<Task> cursor = taskService.query(Query.select(Task.ID, Task.TITLE,
|
||||
Task.IMPORTANCE, Task.DUE_DATE).where(Criterion.and(TaskCriteria.isActive(),
|
||||
TaskCriteria.isVisible())).
|
||||
orderBy(TaskService.defaultTaskOrder()).limit(MAX_NUMBER_OF_TASKS));
|
||||
try {
|
||||
int[] importanceColors = Task.getImportanceColors(ctx.getResources());
|
||||
Task task = new Task();
|
||||
for (int i = 0; i < cursor.getCount(); i++) {
|
||||
cursor.moveToNext();
|
||||
task.readFromCursor(cursor);
|
||||
|
||||
StringBuilder taskTags = new StringBuilder();
|
||||
TodorooCursor<Metadata> tagCursor = TagService.getInstance().getTags(task.getId());
|
||||
try {
|
||||
for(tagCursor.moveToFirst(); !tagCursor.isAfterLast(); tagCursor.moveToNext())
|
||||
taskTags.append(tagCursor.get(TagService.TAG)).append(TAG_SEPARATOR);
|
||||
} finally {
|
||||
tagCursor.close();
|
||||
}
|
||||
|
||||
Object[] values = new Object[7];
|
||||
values[0] = task.getValue(Task.TITLE);
|
||||
values[1] = importanceColors[task.getValue(Task.IMPORTANCE)];
|
||||
values[2] = task.getValue(Task.DUE_DATE);
|
||||
values[3] = task.getValue(Task.DUE_DATE);
|
||||
values[4] = task.getValue(Task.IMPORTANCE);
|
||||
values[5] = task.getId();
|
||||
values[6] = taskTags.toString();
|
||||
|
||||
ret.addRow(values);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
|
||||
if (LOGD)
|
||||
Log.d(TAG, "query");
|
||||
|
||||
Cursor cursor;
|
||||
switch (URI_MATCHER.match(uri)) {
|
||||
|
||||
case URI_TASKS:
|
||||
cursor = getTasks();
|
||||
break;
|
||||
|
||||
case URI_TAGS:
|
||||
cursor = getTags();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unrecognized URI:" + uri);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||
|
||||
if (LOGD)
|
||||
Log.d(TAG, "update");
|
||||
|
||||
switch (URI_MATCHER.match(uri)) {
|
||||
|
||||
case URI_TASKS:
|
||||
Task task = new Task();
|
||||
|
||||
// map values
|
||||
if(values.containsKey(NAME))
|
||||
task.setValue(Task.TITLE, values.getAsString(NAME));
|
||||
if(values.containsKey(PREFERRED_DUE_DATE))
|
||||
task.setValue(Task.DUE_DATE, values.getAsLong(PREFERRED_DUE_DATE));
|
||||
if(values.containsKey(DEFINITE_DUE_DATE))
|
||||
task.setValue(Task.DUE_DATE, values.getAsLong(DEFINITE_DUE_DATE));
|
||||
if(values.containsKey(IMPORTANCE))
|
||||
task.setValue(Task.IMPORTANCE, values.getAsInteger(IMPORTANCE));
|
||||
if(values.containsKey(COMPLETED))
|
||||
task.setValue(Task.COMPLETION_DATE,
|
||||
values.getAsBoolean(COMPLETED) ? DateUtilities.now() : 0);
|
||||
|
||||
// map selection criteria
|
||||
String criteria = selection.replace(NAME, Task.TITLE.name).
|
||||
replace(PREFERRED_DUE_DATE, Task.DUE_DATE.name).
|
||||
replace(DEFINITE_DUE_DATE, Task.DUE_DATE.name).
|
||||
replace(IDENTIFIER, Task.ID.name).
|
||||
replace(ID, Task.ID.name).
|
||||
replace(IMPORTANCE, Task.IMPORTANCE.name);
|
||||
|
||||
return taskService.updateBySelection(criteria, selectionArgs, task);
|
||||
|
||||
case URI_TAGS:
|
||||
throw new UnsupportedOperationException("tags updating: not yet");
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unrecognized URI:" + uri);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyDatabaseModification() {
|
||||
|
||||
if (LOGD)
|
||||
Log.d(TAG, "notifyDatabaseModification");
|
||||
|
||||
ctx.getContentResolver().notifyChange(CONTENT_URI, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,144 +1,144 @@
|
||||
package com.todoroo.astrid.widget;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.activity.TaskEditActivity;
|
||||
import com.todoroo.astrid.activity.TaskListActivity;
|
||||
import com.todoroo.astrid.api.Filter;
|
||||
import com.todoroo.astrid.core.CoreFilterExposer;
|
||||
import com.todoroo.astrid.dao.Database;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||
import com.todoroo.astrid.service.TaskService;
|
||||
|
||||
public class TasksWidget extends AppWidgetProvider {
|
||||
|
||||
static {
|
||||
AstridDependencyInjector.initialize();
|
||||
}
|
||||
|
||||
public final static int[] TEXT_IDS = { R.id.task_1, R.id.task_2,
|
||||
R.id.task_3, R.id.task_4, R.id.task_5 };
|
||||
public final static int[] SEPARATOR_IDS = { R.id.separator_1,
|
||||
R.id.separator_2, R.id.separator_3, R.id.separator_4 };
|
||||
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
|
||||
int[] appWidgetIds) {
|
||||
|
||||
try {
|
||||
super.onUpdate(context, appWidgetManager, appWidgetIds);
|
||||
|
||||
// Start in service to prevent Application Not Responding timeout
|
||||
context.startService(new Intent(context, UpdateService.class));
|
||||
} catch (SecurityException e) {
|
||||
// :(
|
||||
}
|
||||
}
|
||||
|
||||
public static class UpdateService extends Service {
|
||||
|
||||
@Autowired
|
||||
Database database;
|
||||
|
||||
@Autowired
|
||||
TaskService taskService;
|
||||
|
||||
@Override
|
||||
public void onStart(Intent intent, int startId) {
|
||||
ContextManager.setContext(this);
|
||||
RemoteViews updateViews = buildUpdate(this);
|
||||
|
||||
ComponentName thisWidget = new ComponentName(this,
|
||||
TasksWidget.class);
|
||||
AppWidgetManager manager = AppWidgetManager.getInstance(this);
|
||||
manager.updateAppWidget(thisWidget, updateViews);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public RemoteViews buildUpdate(Context context) {
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
|
||||
RemoteViews views = null;
|
||||
|
||||
views = new RemoteViews(context.getPackageName(),
|
||||
R.layout.widget_initialized);
|
||||
|
||||
int[] textIDs = TEXT_IDS;
|
||||
int[] separatorIDs = SEPARATOR_IDS;
|
||||
int numberOfTasks = 5;
|
||||
|
||||
Intent listIntent = new Intent(context, TaskListActivity.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
|
||||
listIntent, 0);
|
||||
views.setOnClickPendingIntent(R.id.taskbody, pendingIntent);
|
||||
|
||||
TodorooCursor<Task> cursor = null;
|
||||
try {
|
||||
Filter inboxFilter = CoreFilterExposer.buildInboxFilter(getResources());
|
||||
inboxFilter.sqlQuery += "ORDER BY " + TaskService.defaultTaskOrder() + " LIMIT " + numberOfTasks;
|
||||
|
||||
database.openForReading();
|
||||
cursor = taskService.fetchFiltered(inboxFilter, null, Task.TITLE, Task.DUE_DATE);
|
||||
Task task = new Task();
|
||||
for (int i = 0; i < cursor.getCount(); i++) {
|
||||
cursor.moveToPosition(i);
|
||||
task.readFromCursor(cursor);
|
||||
|
||||
String textContent = "";
|
||||
int textColor = Color.WHITE;
|
||||
|
||||
textContent = task.getValue(Task.TITLE);
|
||||
if(task.hasDueDate() && task.getValue(Task.DUE_DATE) < DateUtilities.now())
|
||||
textColor = context.getResources().getColor(R.color.task_list_overdue);
|
||||
|
||||
if(i > 0)
|
||||
views.setViewVisibility(separatorIDs[i-1], View.VISIBLE);
|
||||
views.setTextViewText(textIDs[i], textContent);
|
||||
views.setTextColor(textIDs[i], textColor);
|
||||
}
|
||||
|
||||
for(int i = cursor.getCount() - 1; i < separatorIDs.length; i++) {
|
||||
if(i >= 0)
|
||||
views.setViewVisibility(separatorIDs[i], View.INVISIBLE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// can happen if database is not ready
|
||||
Log.e("WIDGET-UPDATE", "Error updating widget", e);
|
||||
} finally {
|
||||
if(cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
Intent editIntent = new Intent(context, TaskEditActivity.class);
|
||||
pendingIntent = PendingIntent.getActivity(context, 0,
|
||||
editIntent, 0);
|
||||
views.setOnClickPendingIntent(R.id.widget_button, pendingIntent);
|
||||
|
||||
return views;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
package com.todoroo.astrid.widget;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.timsu.astrid.R;
|
||||
import com.todoroo.andlib.data.TodorooCursor;
|
||||
import com.todoroo.andlib.service.Autowired;
|
||||
import com.todoroo.andlib.service.ContextManager;
|
||||
import com.todoroo.andlib.service.DependencyInjectionService;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import com.todoroo.astrid.activity.TaskEditActivity;
|
||||
import com.todoroo.astrid.activity.TaskListActivity;
|
||||
import com.todoroo.astrid.api.Filter;
|
||||
import com.todoroo.astrid.core.CoreFilterExposer;
|
||||
import com.todoroo.astrid.dao.Database;
|
||||
import com.todoroo.astrid.model.Task;
|
||||
import com.todoroo.astrid.service.AstridDependencyInjector;
|
||||
import com.todoroo.astrid.service.TaskService;
|
||||
|
||||
public class TasksWidget extends AppWidgetProvider {
|
||||
|
||||
static {
|
||||
AstridDependencyInjector.initialize();
|
||||
}
|
||||
|
||||
public final static int[] TEXT_IDS = { R.id.task_1, R.id.task_2,
|
||||
R.id.task_3, R.id.task_4, R.id.task_5 };
|
||||
public final static int[] SEPARATOR_IDS = { R.id.separator_1,
|
||||
R.id.separator_2, R.id.separator_3, R.id.separator_4 };
|
||||
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
|
||||
int[] appWidgetIds) {
|
||||
|
||||
try {
|
||||
super.onUpdate(context, appWidgetManager, appWidgetIds);
|
||||
|
||||
// Start in service to prevent Application Not Responding timeout
|
||||
context.startService(new Intent(context, UpdateService.class));
|
||||
} catch (SecurityException e) {
|
||||
// :(
|
||||
}
|
||||
}
|
||||
|
||||
public static class UpdateService extends Service {
|
||||
|
||||
@Autowired
|
||||
Database database;
|
||||
|
||||
@Autowired
|
||||
TaskService taskService;
|
||||
|
||||
@Override
|
||||
public void onStart(Intent intent, int startId) {
|
||||
ContextManager.setContext(this);
|
||||
RemoteViews updateViews = buildUpdate(this);
|
||||
|
||||
ComponentName thisWidget = new ComponentName(this,
|
||||
TasksWidget.class);
|
||||
AppWidgetManager manager = AppWidgetManager.getInstance(this);
|
||||
manager.updateAppWidget(thisWidget, updateViews);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public RemoteViews buildUpdate(Context context) {
|
||||
DependencyInjectionService.getInstance().inject(this);
|
||||
|
||||
RemoteViews views = null;
|
||||
|
||||
views = new RemoteViews(context.getPackageName(),
|
||||
R.layout.widget_initialized);
|
||||
|
||||
int[] textIDs = TEXT_IDS;
|
||||
int[] separatorIDs = SEPARATOR_IDS;
|
||||
int numberOfTasks = 5;
|
||||
|
||||
Intent listIntent = new Intent(context, TaskListActivity.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
|
||||
listIntent, 0);
|
||||
views.setOnClickPendingIntent(R.id.taskbody, pendingIntent);
|
||||
|
||||
TodorooCursor<Task> cursor = null;
|
||||
try {
|
||||
Filter inboxFilter = CoreFilterExposer.buildInboxFilter(getResources());
|
||||
inboxFilter.sqlQuery += "ORDER BY " + TaskService.defaultTaskOrder() + " LIMIT " + numberOfTasks;
|
||||
|
||||
database.openForReading();
|
||||
cursor = taskService.fetchFiltered(inboxFilter, null, Task.TITLE, Task.DUE_DATE);
|
||||
Task task = new Task();
|
||||
for (int i = 0; i < cursor.getCount(); i++) {
|
||||
cursor.moveToPosition(i);
|
||||
task.readFromCursor(cursor);
|
||||
|
||||
String textContent = "";
|
||||
int textColor = Color.WHITE;
|
||||
|
||||
textContent = task.getValue(Task.TITLE);
|
||||
if(task.hasDueDate() && task.getValue(Task.DUE_DATE) < DateUtilities.now())
|
||||
textColor = context.getResources().getColor(R.color.task_list_overdue);
|
||||
|
||||
if(i > 0)
|
||||
views.setViewVisibility(separatorIDs[i-1], View.VISIBLE);
|
||||
views.setTextViewText(textIDs[i], textContent);
|
||||
views.setTextColor(textIDs[i], textColor);
|
||||
}
|
||||
|
||||
for(int i = cursor.getCount() - 1; i < separatorIDs.length; i++) {
|
||||
if(i >= 0)
|
||||
views.setViewVisibility(separatorIDs[i], View.INVISIBLE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// can happen if database is not ready
|
||||
Log.e("WIDGET-UPDATE", "Error updating widget", e);
|
||||
} finally {
|
||||
if(cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
Intent editIntent = new Intent(context, TaskEditActivity.class);
|
||||
pendingIntent = PendingIntent.getActivity(context, 0,
|
||||
editIntent, 0);
|
||||
views.setOnClickPendingIntent(R.id.widget_button, pendingIntent);
|
||||
|
||||
return views;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
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";
|
||||
}
|
||||
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,89 +1,89 @@
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
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,68 +1,68 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
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,7 +1,7 @@
|
||||
package com.todoroo.andlib;
|
||||
|
||||
public class EqCriterion extends UnaryCriterion {
|
||||
EqCriterion(Field field, Object value) {
|
||||
super(field, Operator.eq, value);
|
||||
}
|
||||
}
|
||||
package com.todoroo.andlib;
|
||||
|
||||
public class EqCriterion extends UnaryCriterion {
|
||||
EqCriterion(Field field, Object value) {
|
||||
super(field, Operator.eq, value);
|
||||
}
|
||||
}
|
||||
|
@ -1,90 +1,90 @@
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
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,14 +1,14 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
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,43 +1,43 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
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,5 +1,5 @@
|
||||
package com.todoroo.andlib;
|
||||
|
||||
public enum JoinType {
|
||||
INNER, LEFT, RIGHT, OUT
|
||||
}
|
||||
package com.todoroo.andlib;
|
||||
|
||||
public enum JoinType {
|
||||
INNER, LEFT, RIGHT, OUT
|
||||
}
|
||||
|
@ -1,57 +1,57 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
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,30 +1,30 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
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,5 +1,5 @@
|
||||
package com.todoroo.andlib;
|
||||
|
||||
public enum OrderType {
|
||||
DESC, ASC
|
||||
}
|
||||
package com.todoroo.andlib;
|
||||
|
||||
public enum OrderType {
|
||||
DESC, ASC
|
||||
}
|
||||
|
@ -1,192 +1,192 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
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,117 +1,117 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
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,20 +1,20 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
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,92 +1,92 @@
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue