mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-30 13:12:25 -05:00
Whitespace cleanup
This commit is contained in:
parent
83d5102f3d
commit
f1e433e6df
@ -426,18 +426,18 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
|
|||||||
* Creates and initializes the special accounts ('Unified Inbox' and 'All Messages')
|
* Creates and initializes the special accounts ('Unified Inbox' and 'All Messages')
|
||||||
*/
|
*/
|
||||||
private void createSpecialAccounts() {
|
private void createSpecialAccounts() {
|
||||||
// create the unified inbox meta account ( all accounts is default when none specified )
|
// create the unified inbox meta account ( all accounts is default when none specified )
|
||||||
String name = getString(R.string.integrated_inbox_title);
|
String name = getString(R.string.integrated_inbox_title);
|
||||||
LocalSearch tmpSearch = new LocalSearch(name);
|
LocalSearch tmpSearch = new LocalSearch(name);
|
||||||
tmpSearch.addAllowedFolder(SearchSpecification.GENERIC_INBOX_NAME);
|
tmpSearch.addAllowedFolder(SearchSpecification.GENERIC_INBOX_NAME);
|
||||||
integratedInboxAccount = new SearchAccount(tmpSearch, name,
|
integratedInboxAccount = new SearchAccount(tmpSearch, name,
|
||||||
getString(R.string.integrated_inbox_detail));
|
getString(R.string.integrated_inbox_detail));
|
||||||
|
|
||||||
// create the all messages search ( all accounts is default when none specified )
|
// create the all messages search ( all accounts is default when none specified )
|
||||||
name = getString(R.string.search_all_messages_title);
|
name = getString(R.string.search_all_messages_title);
|
||||||
tmpSearch = new LocalSearch(name);
|
tmpSearch = new LocalSearch(name);
|
||||||
unreadAccount = new SearchAccount(tmpSearch, name,
|
unreadAccount = new SearchAccount(tmpSearch, name,
|
||||||
getString(R.string.search_all_messages_detail));
|
getString(R.string.search_all_messages_detail));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -563,7 +563,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
|
|||||||
final SearchAccount searchAccount = (SearchAccount)account;
|
final SearchAccount searchAccount = (SearchAccount)account;
|
||||||
|
|
||||||
MessagingController.getInstance(getApplication())
|
MessagingController.getInstance(getApplication())
|
||||||
.searchLocalMessages(searchAccount.getRelatedSearch(), new MessagingListener() {
|
.searchLocalMessages(searchAccount.getRelatedSearch(), new MessagingListener() {
|
||||||
@Override
|
@Override
|
||||||
public void searchStats(AccountStats stats) {
|
public void searchStats(AccountStats stats) {
|
||||||
mListener.accountStatusChanged(searchAccount, stats);
|
mListener.accountStatusChanged(searchAccount, stats);
|
||||||
@ -637,9 +637,9 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
|
|||||||
if (K9.FOLDER_NONE.equals(realAccount.getAutoExpandFolderName())) {
|
if (K9.FOLDER_NONE.equals(realAccount.getAutoExpandFolderName())) {
|
||||||
FolderList.actionHandleAccount(this, realAccount);
|
FolderList.actionHandleAccount(this, realAccount);
|
||||||
} else {
|
} else {
|
||||||
LocalSearch search = new LocalSearch(realAccount.getAutoExpandFolderName());
|
LocalSearch search = new LocalSearch(realAccount.getAutoExpandFolderName());
|
||||||
search.addAllowedFolder(realAccount.getAutoExpandFolderName());
|
search.addAllowedFolder(realAccount.getAutoExpandFolderName());
|
||||||
search.addAccountUuid(realAccount.getUuid());
|
search.addAccountUuid(realAccount.getUuid());
|
||||||
MessageList.actionDisplaySearch(this, search, true);}
|
MessageList.actionDisplaySearch(this, search, true);}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -1786,18 +1786,18 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
|
|||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
final String description = getString(R.string.search_title, account.getDescription(), getString(searchModifier.resId));
|
final String description = getString(R.string.search_title, account.getDescription(), getString(searchModifier.resId));
|
||||||
LocalSearch search = null;
|
LocalSearch search = null;
|
||||||
|
|
||||||
if (account instanceof SearchAccount) {
|
if (account instanceof SearchAccount) {
|
||||||
search = ((SearchAccount) account).getRelatedSearch();
|
search = ((SearchAccount) account).getRelatedSearch();
|
||||||
search.setName(description);
|
search.setName(description);
|
||||||
} else {
|
} else {
|
||||||
search = new LocalSearch(description);
|
search = new LocalSearch(description);
|
||||||
search.addAccountUuid(account.getUuid());
|
search.addAccountUuid(account.getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
search.allRequiredFlags(searchModifier.requiredFlags);
|
search.allRequiredFlags(searchModifier.requiredFlags);
|
||||||
search.allForbiddenFlags(searchModifier.forbiddenFlags);
|
search.allForbiddenFlags(searchModifier.forbiddenFlags);
|
||||||
MessageList.actionDisplaySearch(Accounts.this, search, false);
|
MessageList.actionDisplaySearch(Accounts.this, search, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -622,9 +622,9 @@ public class FolderList extends K9ListActivity implements OnNavigationListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onOpenFolder(String folder) {
|
private void onOpenFolder(String folder) {
|
||||||
LocalSearch search = new LocalSearch(folder);
|
LocalSearch search = new LocalSearch(folder);
|
||||||
search.addAccountUuid(mAccount.getUuid());
|
search.addAccountUuid(mAccount.getUuid());
|
||||||
search.addAllowedFolder(folder);
|
search.addAllowedFolder(folder);
|
||||||
MessageList.actionDisplaySearch(this, search, false);
|
MessageList.actionDisplaySearch(this, search, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1265,18 +1265,18 @@ public class FolderList extends K9ListActivity implements OnNavigationListener {
|
|||||||
final String description = getString(R.string.search_title,
|
final String description = getString(R.string.search_title,
|
||||||
getString(R.string.message_list_title, account.getDescription(), displayName),
|
getString(R.string.message_list_title, account.getDescription(), displayName),
|
||||||
getString(searchModifier.resId));
|
getString(searchModifier.resId));
|
||||||
|
|
||||||
LocalSearch search = new LocalSearch(description);
|
LocalSearch search = new LocalSearch(description);
|
||||||
try {
|
try {
|
||||||
search.allRequiredFlags(searchModifier.requiredFlags);
|
search.allRequiredFlags(searchModifier.requiredFlags);
|
||||||
search.allForbiddenFlags(searchModifier.forbiddenFlags);
|
search.allForbiddenFlags(searchModifier.forbiddenFlags);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
search.addAllowedFolder(folderName);
|
search.addAllowedFolder(folderName);
|
||||||
search.addAccountUuid(account.getUuid());
|
search.addAccountUuid(account.getUuid());
|
||||||
MessageList.actionDisplaySearch(FolderList.this, search, false);
|
MessageList.actionDisplaySearch(FolderList.this, search, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1285,11 +1285,11 @@ public class FolderList extends K9ListActivity implements OnNavigationListener {
|
|||||||
LocalSearch search = new LocalSearch(description);
|
LocalSearch search = new LocalSearch(description);
|
||||||
search.addAccountUuid(account.getUuid());
|
search.addAccountUuid(account.getUuid());
|
||||||
try {
|
try {
|
||||||
search.allRequiredFlags(new Flag[]{Flag.SEEN});
|
search.allRequiredFlags(new Flag[]{Flag.SEEN});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,8 +48,8 @@ import com.fsck.k9.search.SearchSpecification.SearchCondition;
|
|||||||
*/
|
*/
|
||||||
public class MessageList extends K9FragmentActivity implements MessageListFragmentListener,
|
public class MessageList extends K9FragmentActivity implements MessageListFragmentListener,
|
||||||
OnBackStackChangedListener, OnSwipeGestureListener {
|
OnBackStackChangedListener, OnSwipeGestureListener {
|
||||||
|
|
||||||
// for this activity
|
// for this activity
|
||||||
private static final String EXTRA_SEARCH = "search";
|
private static final String EXTRA_SEARCH = "search";
|
||||||
|
|
||||||
// used for remote search
|
// used for remote search
|
||||||
@ -59,22 +59,22 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme
|
|||||||
public static void actionDisplaySearch(Context context, SearchSpecification search, boolean newTask) {
|
public static void actionDisplaySearch(Context context, SearchSpecification search, boolean newTask) {
|
||||||
actionDisplaySearch(context, search, newTask, true);
|
actionDisplaySearch(context, search, newTask, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void actionDisplaySearch(Context context, SearchSpecification search, boolean newTask, boolean clearTop) {
|
public static void actionDisplaySearch(Context context, SearchSpecification search, boolean newTask, boolean clearTop) {
|
||||||
context.startActivity(intentDisplaySearch(context, search, newTask, clearTop));
|
context.startActivity(intentDisplaySearch(context, search, newTask, clearTop));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Intent intentDisplaySearch(Context context, SearchSpecification search, boolean newTask, boolean clearTop) {
|
public static Intent intentDisplaySearch(Context context, SearchSpecification search, boolean newTask, boolean clearTop) {
|
||||||
Intent intent = new Intent(context, MessageList.class);
|
Intent intent = new Intent(context, MessageList.class);
|
||||||
intent.putExtra(EXTRA_SEARCH, search);
|
intent.putExtra(EXTRA_SEARCH, search);
|
||||||
|
|
||||||
if (clearTop) {
|
if (clearTop) {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||||
}
|
}
|
||||||
if (newTask) {
|
if (newTask) {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,11 +91,11 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme
|
|||||||
|
|
||||||
private Account mAccount;
|
private Account mAccount;
|
||||||
private String mFolderName;
|
private String mFolderName;
|
||||||
private LocalSearch mSearch;
|
private LocalSearch mSearch;
|
||||||
private boolean mSingleFolderMode;
|
private boolean mSingleFolderMode;
|
||||||
private boolean mSingleAccountMode;
|
private boolean mSingleAccountMode;
|
||||||
private boolean mIsRemote;
|
private boolean mIsRemote;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -123,8 +123,8 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void decodeExtras(Intent intent) {
|
private void decodeExtras(Intent intent) {
|
||||||
// check if this intent comes from the system search ( remote )
|
// check if this intent comes from the system search ( remote )
|
||||||
if (intent.getStringExtra(SearchManager.QUERY) != null) {
|
if (intent.getStringExtra(SearchManager.QUERY) != null) {
|
||||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||||
//Query was received from Search Dialog
|
//Query was received from Search Dialog
|
||||||
Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
|
Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
|
||||||
@ -132,40 +132,40 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme
|
|||||||
mSearch = new LocalSearch();
|
mSearch = new LocalSearch();
|
||||||
mSearch.addAccountUuid(appData.getString(EXTRA_SEARCH_ACCOUNT));
|
mSearch.addAccountUuid(appData.getString(EXTRA_SEARCH_ACCOUNT));
|
||||||
mSearch.addAllowedFolder(appData.getString(EXTRA_SEARCH_FOLDER));
|
mSearch.addAllowedFolder(appData.getString(EXTRA_SEARCH_FOLDER));
|
||||||
|
|
||||||
String query = intent.getStringExtra(SearchManager.QUERY);
|
String query = intent.getStringExtra(SearchManager.QUERY);
|
||||||
mSearch.or(new SearchCondition(SEARCHFIELD.SENDER, ATTRIBUTE.CONTAINS, query));
|
mSearch.or(new SearchCondition(SEARCHFIELD.SENDER, ATTRIBUTE.CONTAINS, query));
|
||||||
mSearch.or(new SearchCondition(SEARCHFIELD.SUBJECT, ATTRIBUTE.CONTAINS, query));
|
mSearch.or(new SearchCondition(SEARCHFIELD.SUBJECT, ATTRIBUTE.CONTAINS, query));
|
||||||
|
|
||||||
mIsRemote = true;
|
mIsRemote = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// regular LocalSearch object was passed
|
// regular LocalSearch object was passed
|
||||||
mSearch = intent.getParcelableExtra(EXTRA_SEARCH);
|
mSearch = intent.getParcelableExtra(EXTRA_SEARCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] accounts = mSearch.getAccountUuids();
|
String[] accounts = mSearch.getAccountUuids();
|
||||||
mSingleAccountMode = ( accounts != null && accounts.length == 1
|
mSingleAccountMode = ( accounts != null && accounts.length == 1
|
||||||
&& !accounts[0].equals(SearchSpecification.ALL_ACCOUNTS));
|
&& !accounts[0].equals(SearchSpecification.ALL_ACCOUNTS));
|
||||||
mSingleFolderMode = mSingleAccountMode && (mSearch.getFolderNames().size() == 1);
|
mSingleFolderMode = mSingleAccountMode && (mSearch.getFolderNames().size() == 1);
|
||||||
|
|
||||||
if (mSingleAccountMode) {
|
if (mSingleAccountMode) {
|
||||||
mAccount = Preferences.getPreferences(this).getAccount(accounts[0]);
|
mAccount = Preferences.getPreferences(this).getAccount(accounts[0]);
|
||||||
|
|
||||||
if (mAccount != null && !mAccount.isAvailable(this)) {
|
if (mAccount != null && !mAccount.isAvailable(this)) {
|
||||||
Log.i(K9.LOG_TAG, "not opening MessageList of unavailable account");
|
Log.i(K9.LOG_TAG, "not opening MessageList of unavailable account");
|
||||||
onAccountUnavailable();
|
onAccountUnavailable();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSingleFolderMode) {
|
if (mSingleFolderMode) {
|
||||||
mFolderName = mSearch.getFolderNames().get(0);
|
mFolderName = mSearch.getFolderNames().get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we know if we are in single account mode and need a subtitle
|
// now we know if we are in single account mode and need a subtitle
|
||||||
mActionBarSubTitle.setVisibility((!mSingleFolderMode) ? View.GONE : View.VISIBLE);
|
mActionBarSubTitle.setVisibility((!mSingleFolderMode) ? View.GONE : View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -329,10 +329,10 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme
|
|||||||
if (fragmentManager.getBackStackEntryCount() > 0) {
|
if (fragmentManager.getBackStackEntryCount() > 0) {
|
||||||
fragmentManager.popBackStack();
|
fragmentManager.popBackStack();
|
||||||
} else if (!mSingleFolderMode) {
|
} else if (!mSingleFolderMode) {
|
||||||
onBackPressed();
|
onBackPressed();
|
||||||
} else {
|
} else {
|
||||||
onShowFolderList();
|
onShowFolderList();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case R.id.compose: {
|
case R.id.compose: {
|
||||||
@ -581,10 +581,10 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showMoreFromSameSender(String senderAddress) {
|
public void showMoreFromSameSender(String senderAddress) {
|
||||||
LocalSearch tmpSearch = new LocalSearch("From " + senderAddress);
|
LocalSearch tmpSearch = new LocalSearch("From " + senderAddress);
|
||||||
tmpSearch.addAccountUuids(mSearch.getAccountUuids());
|
tmpSearch.addAccountUuids(mSearch.getAccountUuids());
|
||||||
tmpSearch.and(SEARCHFIELD.SENDER, senderAddress, ATTRIBUTE.CONTAINS);
|
tmpSearch.and(SEARCHFIELD.SENDER, senderAddress, ATTRIBUTE.CONTAINS);
|
||||||
|
|
||||||
MessageListFragment fragment = MessageListFragment.newInstance(tmpSearch, false);
|
MessageListFragment fragment = MessageListFragment.newInstance(tmpSearch, false);
|
||||||
|
|
||||||
addMessageListFragment(fragment);
|
addMessageListFragment(fragment);
|
||||||
@ -668,10 +668,10 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showThread(Account account, String folderName, long threadRootId) {
|
public void showThread(Account account, String folderName, long threadRootId) {
|
||||||
LocalSearch tmpSearch = new LocalSearch();
|
LocalSearch tmpSearch = new LocalSearch();
|
||||||
tmpSearch.addAccountUuids(mSearch.getAccountUuids());
|
tmpSearch.addAccountUuids(mSearch.getAccountUuids());
|
||||||
tmpSearch.and(SEARCHFIELD.THREAD_ROOT, String.valueOf(threadRootId), ATTRIBUTE.EQUALS);
|
tmpSearch.and(SEARCHFIELD.THREAD_ROOT, String.valueOf(threadRootId), ATTRIBUTE.EQUALS);
|
||||||
|
|
||||||
MessageListFragment fragment = MessageListFragment.newInstance(tmpSearch, false);
|
MessageListFragment fragment = MessageListFragment.newInstance(tmpSearch, false);
|
||||||
addMessageListFragment(fragment);
|
addMessageListFragment(fragment);
|
||||||
}
|
}
|
||||||
|
@ -632,20 +632,20 @@ public class MessagingController implements Runnable {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void searchLocalMessagesSynchronous(final LocalSearch search, final MessagingListener listener) {
|
public void searchLocalMessagesSynchronous(final LocalSearch search, final MessagingListener listener) {
|
||||||
final AccountStats stats = new AccountStats();
|
final AccountStats stats = new AccountStats();
|
||||||
final HashSet<String> uuidSet = new HashSet<String>(Arrays.asList(search.getAccountUuids()));
|
final HashSet<String> uuidSet = new HashSet<String>(Arrays.asList(search.getAccountUuids()));
|
||||||
Account[] accounts = Preferences.getPreferences(mApplication.getApplicationContext()).getAccounts();
|
Account[] accounts = Preferences.getPreferences(mApplication.getApplicationContext()).getAccounts();
|
||||||
boolean allAccounts = uuidSet.contains(SearchSpecification.ALL_ACCOUNTS);
|
boolean allAccounts = uuidSet.contains(SearchSpecification.ALL_ACCOUNTS);
|
||||||
|
|
||||||
// for every account we want to search do the query in the localstore
|
// for every account we want to search do the query in the localstore
|
||||||
for (final Account account : accounts) {
|
for (final Account account : accounts) {
|
||||||
|
|
||||||
if (!allAccounts && !uuidSet.contains(account.getUuid())) {
|
if (!allAccounts && !uuidSet.contains(account.getUuid())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collecting statistics of the search result
|
// Collecting statistics of the search result
|
||||||
MessageRetrievalListener retrievalListener = new MessageRetrievalListener() {
|
MessageRetrievalListener retrievalListener = new MessageRetrievalListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -666,15 +666,15 @@ public class MessagingController implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// alert everyone the search has started
|
// alert everyone the search has started
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.listLocalMessagesStarted(account, null);
|
listener.listLocalMessagesStarted(account, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// build and do the query in the localstore
|
// build and do the query in the localstore
|
||||||
try {
|
try {
|
||||||
LocalStore localStore = account.getLocalStore();
|
LocalStore localStore = account.getLocalStore();
|
||||||
localStore.searchForMessages(retrievalListener, search);
|
localStore.searchForMessages(retrievalListener, search);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
@ -686,9 +686,9 @@ public class MessagingController implements Runnable {
|
|||||||
listener.listLocalMessagesFinished(account, null);
|
listener.listLocalMessagesFinished(account, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish the total search statistics
|
// publish the total search statistics
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.searchStats(stats);
|
listener.searchStats(stats);
|
||||||
}
|
}
|
||||||
@ -3164,7 +3164,7 @@ public class MessagingController implements Runnable {
|
|||||||
search.addAllowedFolder(account.getInboxFolderName());
|
search.addAllowedFolder(account.getInboxFolderName());
|
||||||
search.addAccountUuid(account.getUuid());
|
search.addAccountUuid(account.getUuid());
|
||||||
Intent intent = MessageList.intentDisplaySearch(mApplication, search, true, true);
|
Intent intent = MessageList.intentDisplaySearch(mApplication, search, true, true);
|
||||||
|
|
||||||
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, intent, 0);
|
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, intent, 0);
|
||||||
builder.setContentIntent(pi);
|
builder.setContentIntent(pi);
|
||||||
|
|
||||||
@ -3250,7 +3250,7 @@ public class MessagingController implements Runnable {
|
|||||||
search.addAllowedFolder(account.getInboxFolderName());
|
search.addAllowedFolder(account.getInboxFolderName());
|
||||||
search.addAccountUuid(account.getUuid());
|
search.addAccountUuid(account.getUuid());
|
||||||
Intent intent = MessageList.intentDisplaySearch(mApplication, search, true, true);
|
Intent intent = MessageList.intentDisplaySearch(mApplication, search, true, true);
|
||||||
|
|
||||||
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, intent, 0);
|
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, intent, 0);
|
||||||
builder.setContentIntent(pi);
|
builder.setContentIntent(pi);
|
||||||
|
|
||||||
|
@ -667,16 +667,16 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
public Long doDbWork(final SQLiteDatabase db) {
|
public Long doDbWork(final SQLiteDatabase db) {
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
try {
|
try {
|
||||||
cursor = db.rawQuery("SELECT id FROM folders WHERE name = '" + name + "'", null);
|
cursor = db.rawQuery("SELECT id FROM folders WHERE name = '" + name + "'", null);
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
return cursor.getLong(0);
|
return cursor.getLong(0);
|
||||||
} finally {
|
} finally {
|
||||||
Utility.closeQuietly(cursor);
|
Utility.closeQuietly(cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this takes about 260-300ms, seems slow.
|
// TODO this takes about 260-300ms, seems slow.
|
||||||
@Override
|
@Override
|
||||||
public List <? extends Folder > getPersonalNamespaces(boolean forceListAll) throws MessagingException {
|
public List <? extends Folder > getPersonalNamespaces(boolean forceListAll) throws MessagingException {
|
||||||
@ -920,7 +920,7 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
}
|
}
|
||||||
int i = 0;
|
int i = 0;
|
||||||
if (str.charAt(0) == '-') {
|
if (str.charAt(0) == '-') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (; i < length; i++) {
|
for (; i < length; i++) {
|
||||||
char c = str.charAt(i);
|
char c = str.charAt(i);
|
||||||
@ -930,36 +930,36 @@ public class LocalStore extends Store implements Serializable {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Message[] searchForMessages(MessageRetrievalListener retrievalListener,
|
|
||||||
LocalSearch search) throws MessagingException {
|
|
||||||
|
|
||||||
// update some references in the search that have to be bound to this one store
|
|
||||||
for (ConditionsTreeNode node : search.getLeafSet()) {
|
|
||||||
if (node.mCondition.field == SEARCHFIELD.FOLDER) {
|
|
||||||
// TODO find better solution
|
|
||||||
if (isFolderId(node.mCondition.value)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.mCondition.value.equals(LocalSearch.GENERIC_INBOX_NAME)) {
|
|
||||||
node.mCondition.value = mAccount.getInboxFolderName();
|
|
||||||
}
|
|
||||||
node.mCondition.value = String.valueOf(getFolderId(node.mCondition.value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// build sql query
|
public Message[] searchForMessages(MessageRetrievalListener retrievalListener,
|
||||||
String sqlQuery = "SELECT " + GET_MESSAGES_COLS + "FROM messages WHERE deleted = 0 "
|
LocalSearch search) throws MessagingException {
|
||||||
+ (search.getConditions() != null ? "AND (" + search.getConditions() + ")" : "") + " ORDER BY date DESC";
|
|
||||||
|
// update some references in the search that have to be bound to this one store
|
||||||
|
for (ConditionsTreeNode node : search.getLeafSet()) {
|
||||||
|
if (node.mCondition.field == SEARCHFIELD.FOLDER) {
|
||||||
|
// TODO find better solution
|
||||||
|
if (isFolderId(node.mCondition.value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.mCondition.value.equals(LocalSearch.GENERIC_INBOX_NAME)) {
|
||||||
|
node.mCondition.value = mAccount.getInboxFolderName();
|
||||||
|
}
|
||||||
|
node.mCondition.value = String.valueOf(getFolderId(node.mCondition.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build sql query
|
||||||
|
String sqlQuery = "SELECT " + GET_MESSAGES_COLS + "FROM messages WHERE deleted = 0 "
|
||||||
|
+ (search.getConditions() != null ? "AND (" + search.getConditions() + ")" : "") + " ORDER BY date DESC";
|
||||||
|
|
||||||
if (K9.DEBUG) {
|
if (K9.DEBUG) {
|
||||||
Log.d(K9.LOG_TAG, "Query = " + sqlQuery);
|
Log.d(K9.LOG_TAG, "Query = " + sqlQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getMessages(retrievalListener, null, sqlQuery, new String[] {});
|
return getMessages(retrievalListener, null, sqlQuery, new String[] {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a query string, actually do the query for the messages and
|
* Given a query string, actually do the query for the messages and
|
||||||
* call the MessageRetrievalListener for each one
|
* call the MessageRetrievalListener for each one
|
||||||
|
@ -63,9 +63,9 @@ public class UnreadWidgetProvider extends AppWidgetProvider {
|
|||||||
clickIntent = FolderList.actionHandleAccountIntent(context, account, null,
|
clickIntent = FolderList.actionHandleAccountIntent(context, account, null,
|
||||||
false);
|
false);
|
||||||
} else {
|
} else {
|
||||||
LocalSearch search = new LocalSearch(account.getAutoExpandFolderName());
|
LocalSearch search = new LocalSearch(account.getAutoExpandFolderName());
|
||||||
search.addAllowedFolder(account.getAutoExpandFolderName());
|
search.addAllowedFolder(account.getAutoExpandFolderName());
|
||||||
search.addAccountUuid(account.getUuid());
|
search.addAccountUuid(account.getUuid());
|
||||||
clickIntent = MessageList.intentDisplaySearch(context, search, true, true);
|
clickIntent = MessageList.intentDisplaySearch(context, search, true, true);
|
||||||
}
|
}
|
||||||
clickIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
clickIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||||
|
@ -14,388 +14,388 @@ import com.fsck.k9.search.SearchSpecification.SEARCHFIELD;
|
|||||||
import com.fsck.k9.search.SearchSpecification.SearchCondition;
|
import com.fsck.k9.search.SearchSpecification.SearchCondition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class stores search conditions. It's basically a boolean expression binary tree.
|
* This class stores search conditions. It's basically a boolean expression binary tree.
|
||||||
* The output will be SQL queries ( obtained by traversing inorder ).
|
* The output will be SQL queries ( obtained by traversing inorder ).
|
||||||
*
|
*
|
||||||
* TODO removing conditions from the tree
|
* TODO removing conditions from the tree
|
||||||
* TODO implement NOT as a node again
|
* TODO implement NOT as a node again
|
||||||
*
|
*
|
||||||
* @author dzan
|
* @author dzan
|
||||||
*/
|
*/
|
||||||
public class ConditionsTreeNode implements Parcelable{
|
public class ConditionsTreeNode implements Parcelable{
|
||||||
|
|
||||||
public enum OPERATOR {
|
public enum OPERATOR {
|
||||||
AND, OR, CONDITION;
|
AND, OR, CONDITION;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConditionsTreeNode mLeft;
|
public ConditionsTreeNode mLeft;
|
||||||
public ConditionsTreeNode mRight;
|
public ConditionsTreeNode mRight;
|
||||||
public ConditionsTreeNode mParent;
|
public ConditionsTreeNode mParent;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If mValue isn't CONDITION then mCondition contains a real
|
* If mValue isn't CONDITION then mCondition contains a real
|
||||||
* condition, otherwise it's null.
|
* condition, otherwise it's null.
|
||||||
*/
|
*/
|
||||||
public OPERATOR mValue;
|
public OPERATOR mValue;
|
||||||
public SearchCondition mCondition;
|
public SearchCondition mCondition;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used for storing and retrieving the tree to/from the database.
|
* Used for storing and retrieving the tree to/from the database.
|
||||||
* The algorithm is called "modified preorder tree traversal".
|
* The algorithm is called "modified preorder tree traversal".
|
||||||
*/
|
*/
|
||||||
public int mLeftMPTTMarker;
|
public int mLeftMPTTMarker;
|
||||||
public int mRightMPTTMarker;
|
public int mRightMPTTMarker;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// Static Helpers to restore a tree from a database cursor
|
// Static Helpers to restore a tree from a database cursor
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
/**
|
/**
|
||||||
* Builds a condition tree starting from a database cursor. The cursor
|
* Builds a condition tree starting from a database cursor. The cursor
|
||||||
* should point to rows representing the nodes of the tree.
|
* should point to rows representing the nodes of the tree.
|
||||||
*
|
*
|
||||||
* @param cursor Cursor pointing to the first of a bunch or rows. Each rows
|
* @param cursor Cursor pointing to the first of a bunch or rows. Each rows
|
||||||
* should contains 1 tree node.
|
* should contains 1 tree node.
|
||||||
* @return A condition tree.
|
* @return A condition tree.
|
||||||
*/
|
*/
|
||||||
public static ConditionsTreeNode buildTreeFromDB(Cursor cursor) {
|
public static ConditionsTreeNode buildTreeFromDB(Cursor cursor) {
|
||||||
Stack<ConditionsTreeNode> stack = new Stack<ConditionsTreeNode>();
|
Stack<ConditionsTreeNode> stack = new Stack<ConditionsTreeNode>();
|
||||||
ConditionsTreeNode tmp = null;
|
ConditionsTreeNode tmp = null;
|
||||||
|
|
||||||
// root node
|
// root node
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
tmp = buildNodeFromRow(cursor);
|
tmp = buildNodeFromRow(cursor);
|
||||||
stack.push(tmp);
|
stack.push(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// other nodes
|
// other nodes
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
tmp = buildNodeFromRow(cursor);
|
tmp = buildNodeFromRow(cursor);
|
||||||
if (tmp.mRightMPTTMarker < stack.peek().mRightMPTTMarker ){
|
if (tmp.mRightMPTTMarker < stack.peek().mRightMPTTMarker ){
|
||||||
stack.peek().mLeft = tmp;
|
stack.peek().mLeft = tmp;
|
||||||
stack.push(tmp);
|
stack.push(tmp);
|
||||||
} else {
|
} else {
|
||||||
while (stack.peek().mRightMPTTMarker < tmp.mRightMPTTMarker) {
|
while (stack.peek().mRightMPTTMarker < tmp.mRightMPTTMarker) {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
}
|
}
|
||||||
stack.peek().mRight = tmp;
|
stack.peek().mRight = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a single database row to a single condition node.
|
|
||||||
*
|
|
||||||
* @param cursor Cursor pointing to the row we want to convert.
|
|
||||||
* @return A single ConditionsTreeNode
|
|
||||||
*/
|
|
||||||
private static ConditionsTreeNode buildNodeFromRow(Cursor cursor) {
|
|
||||||
ConditionsTreeNode result = null;
|
|
||||||
SearchCondition condition = null;
|
|
||||||
|
|
||||||
OPERATOR tmpValue = ConditionsTreeNode.OPERATOR.valueOf(cursor.getString(5));
|
|
||||||
|
|
||||||
if (tmpValue == OPERATOR.CONDITION) {
|
|
||||||
condition = new SearchCondition(SEARCHFIELD.valueOf(cursor.getString(0)),
|
|
||||||
ATTRIBUTE.valueOf(cursor.getString(2)), cursor.getString(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
result = new ConditionsTreeNode(condition);
|
|
||||||
result.mValue = tmpValue;
|
|
||||||
result.mLeftMPTTMarker = cursor.getInt(3);
|
|
||||||
result.mRightMPTTMarker = cursor.getInt(4);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
// Constructors
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
public ConditionsTreeNode(SearchCondition condition) {
|
|
||||||
mParent = null;
|
|
||||||
mCondition = condition;
|
|
||||||
mValue = OPERATOR.CONDITION;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConditionsTreeNode(ConditionsTreeNode parent, OPERATOR op) {
|
/**
|
||||||
mParent = parent;
|
* Converts a single database row to a single condition node.
|
||||||
mValue = op;
|
*
|
||||||
mCondition = null;
|
* @param cursor Cursor pointing to the row we want to convert.
|
||||||
}
|
* @return A single ConditionsTreeNode
|
||||||
|
*/
|
||||||
|
private static ConditionsTreeNode buildNodeFromRow(Cursor cursor) {
|
||||||
///////////////////////////////////////////////////////////////
|
ConditionsTreeNode result = null;
|
||||||
// Public modifiers
|
SearchCondition condition = null;
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
/**
|
|
||||||
* Adds the expression as the second argument of an AND
|
|
||||||
* clause to this node.
|
|
||||||
*
|
|
||||||
* @param expr Expression to 'AND' with.
|
|
||||||
* @return New top AND node.
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public ConditionsTreeNode and(ConditionsTreeNode expr) throws Exception {
|
|
||||||
return add(expr, OPERATOR.AND);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method.
|
|
||||||
* Adds the provided condition as the second argument of an AND
|
|
||||||
* clause to this node.
|
|
||||||
*
|
|
||||||
* @param condition Condition to 'AND' with.
|
|
||||||
* @return New top AND node, new root.
|
|
||||||
*/
|
|
||||||
public ConditionsTreeNode and(SearchCondition condition) {
|
|
||||||
try {
|
|
||||||
ConditionsTreeNode tmp = new ConditionsTreeNode(condition);
|
|
||||||
return and(tmp);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// impossible
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the expression as the second argument of an OR
|
|
||||||
* clause to this node.
|
|
||||||
*
|
|
||||||
* @param expr Expression to 'OR' with.
|
|
||||||
* @return New top OR node.
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public ConditionsTreeNode or(ConditionsTreeNode expr) throws Exception {
|
|
||||||
return add(expr, OPERATOR.OR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method.
|
|
||||||
* Adds the provided condition as the second argument of an OR
|
|
||||||
* clause to this node.
|
|
||||||
*
|
|
||||||
* @param condition Condition to 'OR' with.
|
|
||||||
* @return New top OR node, new root.
|
|
||||||
*/
|
|
||||||
public ConditionsTreeNode or(SearchCondition condition) {
|
|
||||||
try {
|
|
||||||
ConditionsTreeNode tmp = new ConditionsTreeNode(condition);
|
|
||||||
return or(tmp);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// impossible
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This applies the MPTT labeling to the subtree of which this node
|
|
||||||
* is the root node.
|
|
||||||
*
|
|
||||||
* For a description on MPTT see:
|
|
||||||
* http://www.sitepoint.com/hierarchical-data-database-2/
|
|
||||||
*/
|
|
||||||
public void applyMPTTLabel() {
|
|
||||||
applyMPTTLabel(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
// Public accessors
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
/**
|
|
||||||
* Returns the condition stored in this node.
|
|
||||||
* @return Condition stored in the node.
|
|
||||||
*/
|
|
||||||
public SearchCondition getCondition() {
|
|
||||||
return mCondition;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This will traverse the tree inorder and call toString recursively resulting
|
|
||||||
* in a valid SQL where clause.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return (mLeft == null ? "" : "(" + mLeft + ")")
|
|
||||||
+ " " + ( mCondition == null ? mValue.name() : mCondition ) + " "
|
|
||||||
+ (mRight == null ? "" : "(" + mRight + ")") ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a set of all the leaves in the tree.
|
|
||||||
* @return Set of all the leaves.
|
|
||||||
*/
|
|
||||||
public HashSet<ConditionsTreeNode> getLeafSet() {
|
|
||||||
HashSet<ConditionsTreeNode> leafSet = new HashSet<ConditionsTreeNode>();
|
|
||||||
return getLeafSet(leafSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of all the nodes in the subtree of which this node
|
|
||||||
* is the root. The list contains the nodes in a pre traversal order.
|
|
||||||
*
|
|
||||||
* @return List of all nodes in subtree in preorder.
|
|
||||||
*/
|
|
||||||
public List<ConditionsTreeNode> preorder() {
|
|
||||||
ArrayList<ConditionsTreeNode> result = new ArrayList<ConditionsTreeNode>();
|
|
||||||
Stack<ConditionsTreeNode> stack = new Stack<ConditionsTreeNode>();
|
|
||||||
stack.push(this);
|
|
||||||
|
|
||||||
while(!stack.isEmpty()) {
|
|
||||||
ConditionsTreeNode current = stack.pop( );
|
|
||||||
if( current.mLeft != null ) stack.push( current.mLeft );
|
|
||||||
if( current.mRight != null ) stack.push( current.mRight );
|
|
||||||
result.add(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
// Private class logic
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
/**
|
|
||||||
* Adds two new ConditionTreeNodes, one for the operator and one for the
|
|
||||||
* new condition. The current node will end up on the same level as the
|
|
||||||
* one provided in the arguments, they will be siblings. Their common
|
|
||||||
* parent node will be one containing the operator provided in the arguments.
|
|
||||||
* The method will update all the required references so the tree ends up in
|
|
||||||
* a valid state.
|
|
||||||
*
|
|
||||||
* This method only supports node arguments with a null parent node.
|
|
||||||
*
|
|
||||||
* @param Node to add.
|
|
||||||
* @param Operator that will connect the new node with this one.
|
|
||||||
* @return New parent node, containing the operator.
|
|
||||||
* @throws Exception Throws when the provided new node does not have a null parent.
|
|
||||||
*/
|
|
||||||
private ConditionsTreeNode add(ConditionsTreeNode node, OPERATOR op) throws Exception{
|
|
||||||
if (node.mParent != null) {
|
|
||||||
throw new Exception("Can only add new expressions from root node down.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionsTreeNode tmpNode = new ConditionsTreeNode(mParent, op);
|
|
||||||
tmpNode.mLeft = this;
|
|
||||||
tmpNode.mRight = node;
|
|
||||||
|
|
||||||
if (mParent != null) {
|
|
||||||
mParent.updateChild(this, tmpNode);
|
|
||||||
}
|
|
||||||
this.mParent = tmpNode;
|
|
||||||
|
|
||||||
node.mParent = tmpNode;
|
|
||||||
|
|
||||||
return tmpNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
OPERATOR tmpValue = ConditionsTreeNode.OPERATOR.valueOf(cursor.getString(5));
|
||||||
* Helper method that replaces a child of the current node with a new node.
|
|
||||||
* If the provided old child node was the left one, left will be replaced with
|
|
||||||
* the new one. Same goes for the right one.
|
|
||||||
*
|
|
||||||
* @param oldChild Old child node to be replaced.
|
|
||||||
* @param newChild New child node.
|
|
||||||
*/
|
|
||||||
private void updateChild(ConditionsTreeNode oldChild, ConditionsTreeNode newChild) {
|
|
||||||
// we can compare objects id's because this is the desired behaviour in this case
|
|
||||||
if (mLeft == oldChild) {
|
|
||||||
mLeft = newChild;
|
|
||||||
} else if (mRight == oldChild) {
|
|
||||||
mRight = newChild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursive function to gather all the leaves in the subtree of which
|
|
||||||
* this node is the root.
|
|
||||||
*
|
|
||||||
* @param leafSet Leafset that's being built.
|
|
||||||
* @return Set of leaves being completed.
|
|
||||||
*/
|
|
||||||
private HashSet<ConditionsTreeNode> getLeafSet(HashSet<ConditionsTreeNode> leafSet) {
|
|
||||||
// if we ended up in a leaf, add ourself and return
|
|
||||||
if (mLeft == null && mRight == null) {
|
|
||||||
leafSet.add(this);
|
|
||||||
return leafSet;
|
|
||||||
// we didn't end up in a leaf
|
|
||||||
} else {
|
|
||||||
if (mLeft != null) {
|
|
||||||
mLeft.getLeafSet(leafSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mRight != null) {
|
|
||||||
mRight.getLeafSet(leafSet);
|
|
||||||
}
|
|
||||||
return leafSet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This applies the MPTT labeling to the subtree of which this node
|
|
||||||
* is the root node.
|
|
||||||
*
|
|
||||||
* For a description on MPTT see:
|
|
||||||
* http://www.sitepoint.com/hierarchical-data-database-2/
|
|
||||||
*/
|
|
||||||
private int applyMPTTLabel(int label) {
|
|
||||||
mLeftMPTTMarker = label;
|
|
||||||
if (mLeft != null){
|
|
||||||
label = mLeft.applyMPTTLabel(label += 1);
|
|
||||||
}
|
|
||||||
if (mRight != null){
|
|
||||||
label = mRight.applyMPTTLabel(label += 1);
|
|
||||||
}
|
|
||||||
++label;
|
|
||||||
mRightMPTTMarker = label;
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
// Parcelable
|
|
||||||
//
|
|
||||||
// This whole class has to be parcelable because it's passed
|
|
||||||
// on through intents.
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
@Override
|
|
||||||
public int describeContents() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (tmpValue == OPERATOR.CONDITION) {
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
condition = new SearchCondition(SEARCHFIELD.valueOf(cursor.getString(0)),
|
||||||
dest.writeInt(mValue.ordinal());
|
ATTRIBUTE.valueOf(cursor.getString(2)), cursor.getString(1));
|
||||||
dest.writeParcelable(mCondition, flags);
|
}
|
||||||
dest.writeParcelable(mLeft, flags);
|
|
||||||
dest.writeParcelable(mRight, flags);
|
result = new ConditionsTreeNode(condition);
|
||||||
}
|
result.mValue = tmpValue;
|
||||||
|
result.mLeftMPTTMarker = cursor.getInt(3);
|
||||||
public static final Parcelable.Creator<ConditionsTreeNode> CREATOR
|
result.mRightMPTTMarker = cursor.getInt(4);
|
||||||
= new Parcelable.Creator<ConditionsTreeNode>() {
|
|
||||||
public ConditionsTreeNode createFromParcel(Parcel in) {
|
return result;
|
||||||
return new ConditionsTreeNode(in);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public ConditionsTreeNode[] newArray(int size) {
|
///////////////////////////////////////////////////////////////
|
||||||
return new ConditionsTreeNode[size];
|
// Constructors
|
||||||
}
|
///////////////////////////////////////////////////////////////
|
||||||
};
|
public ConditionsTreeNode(SearchCondition condition) {
|
||||||
|
mParent = null;
|
||||||
private ConditionsTreeNode(Parcel in) {
|
mCondition = condition;
|
||||||
mValue = OPERATOR.values()[in.readInt()];
|
mValue = OPERATOR.CONDITION;
|
||||||
mCondition = in.readParcelable(ConditionsTreeNode.class.getClassLoader());
|
}
|
||||||
mLeft = in.readParcelable(ConditionsTreeNode.class.getClassLoader());
|
|
||||||
mRight = in.readParcelable(ConditionsTreeNode.class.getClassLoader());
|
public ConditionsTreeNode(ConditionsTreeNode parent, OPERATOR op) {
|
||||||
mParent = null;
|
mParent = parent;
|
||||||
if (mLeft != null) {
|
mValue = op;
|
||||||
mLeft.mParent = this;
|
mCondition = null;
|
||||||
}
|
}
|
||||||
if (mRight != null) {
|
|
||||||
mRight.mParent = this;
|
|
||||||
}
|
///////////////////////////////////////////////////////////////
|
||||||
}
|
// Public modifiers
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Adds the expression as the second argument of an AND
|
||||||
|
* clause to this node.
|
||||||
|
*
|
||||||
|
* @param expr Expression to 'AND' with.
|
||||||
|
* @return New top AND node.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public ConditionsTreeNode and(ConditionsTreeNode expr) throws Exception {
|
||||||
|
return add(expr, OPERATOR.AND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method.
|
||||||
|
* Adds the provided condition as the second argument of an AND
|
||||||
|
* clause to this node.
|
||||||
|
*
|
||||||
|
* @param condition Condition to 'AND' with.
|
||||||
|
* @return New top AND node, new root.
|
||||||
|
*/
|
||||||
|
public ConditionsTreeNode and(SearchCondition condition) {
|
||||||
|
try {
|
||||||
|
ConditionsTreeNode tmp = new ConditionsTreeNode(condition);
|
||||||
|
return and(tmp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// impossible
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the expression as the second argument of an OR
|
||||||
|
* clause to this node.
|
||||||
|
*
|
||||||
|
* @param expr Expression to 'OR' with.
|
||||||
|
* @return New top OR node.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public ConditionsTreeNode or(ConditionsTreeNode expr) throws Exception {
|
||||||
|
return add(expr, OPERATOR.OR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method.
|
||||||
|
* Adds the provided condition as the second argument of an OR
|
||||||
|
* clause to this node.
|
||||||
|
*
|
||||||
|
* @param condition Condition to 'OR' with.
|
||||||
|
* @return New top OR node, new root.
|
||||||
|
*/
|
||||||
|
public ConditionsTreeNode or(SearchCondition condition) {
|
||||||
|
try {
|
||||||
|
ConditionsTreeNode tmp = new ConditionsTreeNode(condition);
|
||||||
|
return or(tmp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// impossible
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This applies the MPTT labeling to the subtree of which this node
|
||||||
|
* is the root node.
|
||||||
|
*
|
||||||
|
* For a description on MPTT see:
|
||||||
|
* http://www.sitepoint.com/hierarchical-data-database-2/
|
||||||
|
*/
|
||||||
|
public void applyMPTTLabel() {
|
||||||
|
applyMPTTLabel(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
// Public accessors
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Returns the condition stored in this node.
|
||||||
|
* @return Condition stored in the node.
|
||||||
|
*/
|
||||||
|
public SearchCondition getCondition() {
|
||||||
|
return mCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will traverse the tree inorder and call toString recursively resulting
|
||||||
|
* in a valid SQL where clause.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return (mLeft == null ? "" : "(" + mLeft + ")")
|
||||||
|
+ " " + ( mCondition == null ? mValue.name() : mCondition ) + " "
|
||||||
|
+ (mRight == null ? "" : "(" + mRight + ")") ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a set of all the leaves in the tree.
|
||||||
|
* @return Set of all the leaves.
|
||||||
|
*/
|
||||||
|
public HashSet<ConditionsTreeNode> getLeafSet() {
|
||||||
|
HashSet<ConditionsTreeNode> leafSet = new HashSet<ConditionsTreeNode>();
|
||||||
|
return getLeafSet(leafSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all the nodes in the subtree of which this node
|
||||||
|
* is the root. The list contains the nodes in a pre traversal order.
|
||||||
|
*
|
||||||
|
* @return List of all nodes in subtree in preorder.
|
||||||
|
*/
|
||||||
|
public List<ConditionsTreeNode> preorder() {
|
||||||
|
ArrayList<ConditionsTreeNode> result = new ArrayList<ConditionsTreeNode>();
|
||||||
|
Stack<ConditionsTreeNode> stack = new Stack<ConditionsTreeNode>();
|
||||||
|
stack.push(this);
|
||||||
|
|
||||||
|
while(!stack.isEmpty()) {
|
||||||
|
ConditionsTreeNode current = stack.pop( );
|
||||||
|
if( current.mLeft != null ) stack.push( current.mLeft );
|
||||||
|
if( current.mRight != null ) stack.push( current.mRight );
|
||||||
|
result.add(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
// Private class logic
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* Adds two new ConditionTreeNodes, one for the operator and one for the
|
||||||
|
* new condition. The current node will end up on the same level as the
|
||||||
|
* one provided in the arguments, they will be siblings. Their common
|
||||||
|
* parent node will be one containing the operator provided in the arguments.
|
||||||
|
* The method will update all the required references so the tree ends up in
|
||||||
|
* a valid state.
|
||||||
|
*
|
||||||
|
* This method only supports node arguments with a null parent node.
|
||||||
|
*
|
||||||
|
* @param Node to add.
|
||||||
|
* @param Operator that will connect the new node with this one.
|
||||||
|
* @return New parent node, containing the operator.
|
||||||
|
* @throws Exception Throws when the provided new node does not have a null parent.
|
||||||
|
*/
|
||||||
|
private ConditionsTreeNode add(ConditionsTreeNode node, OPERATOR op) throws Exception{
|
||||||
|
if (node.mParent != null) {
|
||||||
|
throw new Exception("Can only add new expressions from root node down.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ConditionsTreeNode tmpNode = new ConditionsTreeNode(mParent, op);
|
||||||
|
tmpNode.mLeft = this;
|
||||||
|
tmpNode.mRight = node;
|
||||||
|
|
||||||
|
if (mParent != null) {
|
||||||
|
mParent.updateChild(this, tmpNode);
|
||||||
|
}
|
||||||
|
this.mParent = tmpNode;
|
||||||
|
|
||||||
|
node.mParent = tmpNode;
|
||||||
|
|
||||||
|
return tmpNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method that replaces a child of the current node with a new node.
|
||||||
|
* If the provided old child node was the left one, left will be replaced with
|
||||||
|
* the new one. Same goes for the right one.
|
||||||
|
*
|
||||||
|
* @param oldChild Old child node to be replaced.
|
||||||
|
* @param newChild New child node.
|
||||||
|
*/
|
||||||
|
private void updateChild(ConditionsTreeNode oldChild, ConditionsTreeNode newChild) {
|
||||||
|
// we can compare objects id's because this is the desired behaviour in this case
|
||||||
|
if (mLeft == oldChild) {
|
||||||
|
mLeft = newChild;
|
||||||
|
} else if (mRight == oldChild) {
|
||||||
|
mRight = newChild;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive function to gather all the leaves in the subtree of which
|
||||||
|
* this node is the root.
|
||||||
|
*
|
||||||
|
* @param leafSet Leafset that's being built.
|
||||||
|
* @return Set of leaves being completed.
|
||||||
|
*/
|
||||||
|
private HashSet<ConditionsTreeNode> getLeafSet(HashSet<ConditionsTreeNode> leafSet) {
|
||||||
|
// if we ended up in a leaf, add ourself and return
|
||||||
|
if (mLeft == null && mRight == null) {
|
||||||
|
leafSet.add(this);
|
||||||
|
return leafSet;
|
||||||
|
// we didn't end up in a leaf
|
||||||
|
} else {
|
||||||
|
if (mLeft != null) {
|
||||||
|
mLeft.getLeafSet(leafSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRight != null) {
|
||||||
|
mRight.getLeafSet(leafSet);
|
||||||
|
}
|
||||||
|
return leafSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This applies the MPTT labeling to the subtree of which this node
|
||||||
|
* is the root node.
|
||||||
|
*
|
||||||
|
* For a description on MPTT see:
|
||||||
|
* http://www.sitepoint.com/hierarchical-data-database-2/
|
||||||
|
*/
|
||||||
|
private int applyMPTTLabel(int label) {
|
||||||
|
mLeftMPTTMarker = label;
|
||||||
|
if (mLeft != null){
|
||||||
|
label = mLeft.applyMPTTLabel(label += 1);
|
||||||
|
}
|
||||||
|
if (mRight != null){
|
||||||
|
label = mRight.applyMPTTLabel(label += 1);
|
||||||
|
}
|
||||||
|
++label;
|
||||||
|
mRightMPTTMarker = label;
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
// Parcelable
|
||||||
|
//
|
||||||
|
// This whole class has to be parcelable because it's passed
|
||||||
|
// on through intents.
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeInt(mValue.ordinal());
|
||||||
|
dest.writeParcelable(mCondition, flags);
|
||||||
|
dest.writeParcelable(mLeft, flags);
|
||||||
|
dest.writeParcelable(mRight, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<ConditionsTreeNode> CREATOR
|
||||||
|
= new Parcelable.Creator<ConditionsTreeNode>() {
|
||||||
|
public ConditionsTreeNode createFromParcel(Parcel in) {
|
||||||
|
return new ConditionsTreeNode(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConditionsTreeNode[] newArray(int size) {
|
||||||
|
return new ConditionsTreeNode[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private ConditionsTreeNode(Parcel in) {
|
||||||
|
mValue = OPERATOR.values()[in.readInt()];
|
||||||
|
mCondition = in.readParcelable(ConditionsTreeNode.class.getClassLoader());
|
||||||
|
mLeft = in.readParcelable(ConditionsTreeNode.class.getClassLoader());
|
||||||
|
mRight = in.readParcelable(ConditionsTreeNode.class.getClassLoader());
|
||||||
|
mParent = null;
|
||||||
|
if (mLeft != null) {
|
||||||
|
mLeft.mParent = this;
|
||||||
|
}
|
||||||
|
if (mRight != null) {
|
||||||
|
mRight.mParent = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,81 +11,81 @@ import android.os.Parcelable;
|
|||||||
import com.fsck.k9.mail.Flag;
|
import com.fsck.k9.mail.Flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a local search.
|
* This class represents a local search.
|
||||||
|
|
||||||
* Removing conditions could be done through matching there unique id in the leafset and then
|
* Removing conditions could be done through matching there unique id in the leafset and then
|
||||||
* removing them from the tree.
|
* removing them from the tree.
|
||||||
*
|
*
|
||||||
* @author dzan
|
* @author dzan
|
||||||
*
|
*
|
||||||
* TODO implement a complete addAllowedFolder method
|
* TODO implement a complete addAllowedFolder method
|
||||||
* TODO conflicting conditions check on add
|
* TODO conflicting conditions check on add
|
||||||
* TODO duplicate condition checking?
|
* TODO duplicate condition checking?
|
||||||
* TODO assign each node a unique id that's used to retrieve it from the leaveset and remove.
|
* TODO assign each node a unique id that's used to retrieve it from the leaveset and remove.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class LocalSearch implements SearchSpecification {
|
public class LocalSearch implements SearchSpecification {
|
||||||
|
|
||||||
private String mName;
|
private String mName;
|
||||||
private boolean mPredefined;
|
private boolean mPredefined;
|
||||||
|
|
||||||
// since the uuid isn't in the message table it's not in the tree neither
|
// since the uuid isn't in the message table it's not in the tree neither
|
||||||
private HashSet<String> mAccountUuids = new HashSet<String>();
|
private HashSet<String> mAccountUuids = new HashSet<String>();
|
||||||
private ConditionsTreeNode mConditions = null;
|
private ConditionsTreeNode mConditions = null;
|
||||||
private HashSet<ConditionsTreeNode> mLeafSet = new HashSet<ConditionsTreeNode>();
|
private HashSet<ConditionsTreeNode> mLeafSet = new HashSet<ConditionsTreeNode>();
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// Constructors
|
// Constructors
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
/**
|
/**
|
||||||
* Use this only if the search won't be saved. Saved searches need
|
* Use this only if the search won't be saved. Saved searches need
|
||||||
* a name!
|
* a name!
|
||||||
*/
|
*/
|
||||||
public LocalSearch(){}
|
public LocalSearch(){}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
*/
|
*/
|
||||||
public LocalSearch(String name) {
|
public LocalSearch(String name) {
|
||||||
this.mName = name;
|
this.mName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this constructor when you know what you'r doing. Normally it's only used
|
* Use this constructor when you know what you'r doing. Normally it's only used
|
||||||
* when restoring these search objects from the database.
|
* when restoring these search objects from the database.
|
||||||
*
|
*
|
||||||
* @param name Name of the search
|
* @param name Name of the search
|
||||||
* @param searchConditions SearchConditions, may contains flags and folders
|
* @param searchConditions SearchConditions, may contains flags and folders
|
||||||
* @param accounts Relative Account's uuid's
|
* @param accounts Relative Account's uuid's
|
||||||
* @param predefined Is this a predefined search or a user created one?
|
* @param predefined Is this a predefined search or a user created one?
|
||||||
*/
|
*/
|
||||||
protected LocalSearch(String name, ConditionsTreeNode searchConditions,
|
protected LocalSearch(String name, ConditionsTreeNode searchConditions,
|
||||||
String accounts, boolean predefined) {
|
String accounts, boolean predefined) {
|
||||||
this(name);
|
this(name);
|
||||||
mConditions = searchConditions;
|
mConditions = searchConditions;
|
||||||
mPredefined = predefined;
|
mPredefined = predefined;
|
||||||
mLeafSet = new HashSet<ConditionsTreeNode>();
|
mLeafSet = new HashSet<ConditionsTreeNode>();
|
||||||
if (mConditions != null) {
|
if (mConditions != null) {
|
||||||
mLeafSet.addAll(mConditions.getLeafSet());
|
mLeafSet.addAll(mConditions.getLeafSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize accounts
|
// initialize accounts
|
||||||
if (accounts != null) {
|
if (accounts != null) {
|
||||||
for (String account : accounts.split(",")) {
|
for (String account : accounts.split(",")) {
|
||||||
mAccountUuids.add(account);
|
mAccountUuids.add(account);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// impossible but still not unrecoverable
|
// impossible but still not unrecoverable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// Public manipulation methods
|
// Public manipulation methods
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
/**
|
/**
|
||||||
* Sets the name of the saved search. If one existed it will
|
* Sets the name of the saved search. If one existed it will
|
||||||
* be overwritten.
|
* be overwritten.
|
||||||
@ -97,215 +97,215 @@ public class LocalSearch implements SearchSpecification {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new account to the search. When no accounts are
|
* Add a new account to the search. When no accounts are
|
||||||
* added manually we search all accounts on the device.
|
* added manually we search all accounts on the device.
|
||||||
*
|
*
|
||||||
* @param uuid Uuid of the account to be added.
|
* @param uuid Uuid of the account to be added.
|
||||||
*/
|
*/
|
||||||
public void addAccountUuid(String uuid) {
|
public void addAccountUuid(String uuid) {
|
||||||
if (uuid.equals(ALL_ACCOUNTS)) {
|
if (uuid.equals(ALL_ACCOUNTS)) {
|
||||||
mAccountUuids.clear();
|
mAccountUuids.clear();
|
||||||
}
|
}
|
||||||
mAccountUuids.add(uuid);
|
mAccountUuids.add(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds all the account uuids in the provided array to
|
* Adds all the account uuids in the provided array to
|
||||||
* be matched by the seach.
|
* be matched by the seach.
|
||||||
*
|
*
|
||||||
* @param accountUuids
|
* @param accountUuids
|
||||||
*/
|
*/
|
||||||
public void addAccountUuids(String[] accountUuids) {
|
public void addAccountUuids(String[] accountUuids) {
|
||||||
for (String acc : accountUuids) {
|
for (String acc : accountUuids) {
|
||||||
addAccountUuid(acc);
|
addAccountUuid(acc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes an account UUID from the current search.
|
* Removes an account UUID from the current search.
|
||||||
*
|
*
|
||||||
* @param uuid Account UUID to remove.
|
* @param uuid Account UUID to remove.
|
||||||
* @return True if removed, false otherwise.
|
* @return True if removed, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean removeAccountUuid(String uuid) {
|
public boolean removeAccountUuid(String uuid) {
|
||||||
return mAccountUuids.remove(uuid);
|
return mAccountUuids.remove(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the provided node as the second argument of an AND
|
* Adds the provided node as the second argument of an AND
|
||||||
* clause to this node.
|
* clause to this node.
|
||||||
*
|
*
|
||||||
* @param field Message table field to match against.
|
* @param field Message table field to match against.
|
||||||
* @param string Value to look for.
|
* @param string Value to look for.
|
||||||
* @param contains Attribute to use when matching.
|
* @param contains Attribute to use when matching.
|
||||||
*
|
*
|
||||||
* @throws IllegalConditionException
|
* @throws IllegalConditionException
|
||||||
*/
|
*/
|
||||||
public void and(SEARCHFIELD field, String value, ATTRIBUTE attribute) {
|
public void and(SEARCHFIELD field, String value, ATTRIBUTE attribute) {
|
||||||
and(new SearchCondition(field, attribute, value));
|
and(new SearchCondition(field, attribute, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the provided condition as the second argument of an AND
|
* Adds the provided condition as the second argument of an AND
|
||||||
* clause to this node.
|
* clause to this node.
|
||||||
*
|
*
|
||||||
* @param condition Condition to 'AND' with.
|
* @param condition Condition to 'AND' with.
|
||||||
* @return New top AND node, new root.
|
* @return New top AND node, new root.
|
||||||
*/
|
*/
|
||||||
public ConditionsTreeNode and(SearchCondition condition) {
|
public ConditionsTreeNode and(SearchCondition condition) {
|
||||||
try {
|
try {
|
||||||
ConditionsTreeNode tmp = new ConditionsTreeNode(condition);
|
ConditionsTreeNode tmp = new ConditionsTreeNode(condition);
|
||||||
return and(tmp);
|
return and(tmp);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// impossible
|
// impossible
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the provided node as the second argument of an AND
|
* Adds the provided node as the second argument of an AND
|
||||||
* clause to this node.
|
* clause to this node.
|
||||||
*
|
*
|
||||||
* @param node Node to 'AND' with.
|
* @param node Node to 'AND' with.
|
||||||
* @return New top AND node, new root.
|
* @return New top AND node, new root.
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public ConditionsTreeNode and(ConditionsTreeNode node) throws Exception {
|
public ConditionsTreeNode and(ConditionsTreeNode node) throws Exception {
|
||||||
mLeafSet.addAll(node.getLeafSet());
|
mLeafSet.addAll(node.getLeafSet());
|
||||||
|
|
||||||
if (mConditions == null) {
|
if (mConditions == null) {
|
||||||
mConditions = node;
|
mConditions = node;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mConditions.and(node);
|
return mConditions.and(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the provided condition as the second argument of an OR
|
* Adds the provided condition as the second argument of an OR
|
||||||
* clause to this node.
|
* clause to this node.
|
||||||
*
|
*
|
||||||
* @param condition Condition to 'OR' with.
|
* @param condition Condition to 'OR' with.
|
||||||
* @return New top OR node, new root.
|
* @return New top OR node, new root.
|
||||||
*/
|
*/
|
||||||
public ConditionsTreeNode or(SearchCondition condition) {
|
public ConditionsTreeNode or(SearchCondition condition) {
|
||||||
try {
|
try {
|
||||||
ConditionsTreeNode tmp = new ConditionsTreeNode(condition);
|
ConditionsTreeNode tmp = new ConditionsTreeNode(condition);
|
||||||
return or(tmp);
|
return or(tmp);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// impossible
|
// impossible
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the provided node as the second argument of an OR
|
* Adds the provided node as the second argument of an OR
|
||||||
* clause to this node.
|
* clause to this node.
|
||||||
*
|
*
|
||||||
* @param node Node to 'OR' with.
|
* @param node Node to 'OR' with.
|
||||||
* @return New top OR node, new root.
|
* @return New top OR node, new root.
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public ConditionsTreeNode or(ConditionsTreeNode node) throws Exception {
|
public ConditionsTreeNode or(ConditionsTreeNode node) throws Exception {
|
||||||
mLeafSet.addAll(node.getLeafSet());
|
mLeafSet.addAll(node.getLeafSet());
|
||||||
|
|
||||||
if (mConditions == null) {
|
if (mConditions == null) {
|
||||||
mConditions = node;
|
mConditions = node;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mConditions.or(node);
|
return mConditions.or(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all the flags to this node as required flags. The
|
* Add all the flags to this node as required flags. The
|
||||||
* provided flags will be combined using AND with the root.
|
* provided flags will be combined using AND with the root.
|
||||||
*
|
*
|
||||||
* @param requiredFlags Array of required flags.
|
* @param requiredFlags Array of required flags.
|
||||||
*/
|
*/
|
||||||
public void allRequiredFlags(Flag[] requiredFlags) {
|
public void allRequiredFlags(Flag[] requiredFlags) {
|
||||||
if (requiredFlags != null) {
|
if (requiredFlags != null) {
|
||||||
for (Flag f : requiredFlags) {
|
for (Flag f : requiredFlags) {
|
||||||
and(new SearchCondition(SEARCHFIELD.FLAG, ATTRIBUTE.CONTAINS, f.name()));
|
and(new SearchCondition(SEARCHFIELD.FLAG, ATTRIBUTE.CONTAINS, f.name()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all the flags to this node as forbidden flags. The
|
* Add all the flags to this node as forbidden flags. The
|
||||||
* provided flags will be combined using AND with the root.
|
* provided flags will be combined using AND with the root.
|
||||||
*
|
*
|
||||||
* @param forbiddenFlags Array of forbidden flags.
|
* @param forbiddenFlags Array of forbidden flags.
|
||||||
*/
|
*/
|
||||||
public void allForbiddenFlags(Flag[] forbiddenFlags) {
|
public void allForbiddenFlags(Flag[] forbiddenFlags) {
|
||||||
if (forbiddenFlags != null) {
|
if (forbiddenFlags != null) {
|
||||||
for (Flag f : forbiddenFlags) {
|
for (Flag f : forbiddenFlags) {
|
||||||
and(new SearchCondition(SEARCHFIELD.FLAG, ATTRIBUTE.NOT_CONTAINS, f.name()));
|
and(new SearchCondition(SEARCHFIELD.FLAG, ATTRIBUTE.NOT_CONTAINS, f.name()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
* FOR NOW: And the folder with the root.
|
* FOR NOW: And the folder with the root.
|
||||||
*
|
*
|
||||||
* Add the folder as another folder to search in. The folder
|
* Add the folder as another folder to search in. The folder
|
||||||
* will be added AND to the root if no 'folder subtree' was found.
|
* will be added AND to the root if no 'folder subtree' was found.
|
||||||
* Otherwise the folder will be added OR to that tree.
|
* Otherwise the folder will be added OR to that tree.
|
||||||
*
|
*
|
||||||
* @param name Name of the folder to add.
|
* @param name Name of the folder to add.
|
||||||
*/
|
*/
|
||||||
public void addAllowedFolder(String name) {
|
public void addAllowedFolder(String name) {
|
||||||
/*
|
/*
|
||||||
* TODO find folder sub-tree
|
* TODO find folder sub-tree
|
||||||
* - do and on root of it & rest of search
|
* - do and on root of it & rest of search
|
||||||
* - do or between folder nodes
|
* - do or between folder nodes
|
||||||
*/
|
*/
|
||||||
and(new SearchCondition(SEARCHFIELD.FOLDER, ATTRIBUTE.EQUALS, name));
|
and(new SearchCondition(SEARCHFIELD.FOLDER, ATTRIBUTE.EQUALS, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO make this more advanced!
|
* TODO make this more advanced!
|
||||||
* This is a temporarely solution that does NOT WORK for
|
* This is a temporarely solution that does NOT WORK for
|
||||||
* real searches because of possible extra conditions to a folder requirement.
|
* real searches because of possible extra conditions to a folder requirement.
|
||||||
*/
|
*/
|
||||||
public List<String> getFolderNames() {
|
public List<String> getFolderNames() {
|
||||||
ArrayList<String> results = new ArrayList<String>();
|
ArrayList<String> results = new ArrayList<String>();
|
||||||
for (ConditionsTreeNode node : mLeafSet) {
|
for (ConditionsTreeNode node : mLeafSet) {
|
||||||
if (node.mCondition.field == SEARCHFIELD.FOLDER
|
if (node.mCondition.field == SEARCHFIELD.FOLDER
|
||||||
&& node.mCondition.attribute == ATTRIBUTE.EQUALS) {
|
&& node.mCondition.attribute == ATTRIBUTE.EQUALS) {
|
||||||
results.add(node.mCondition.value);
|
results.add(node.mCondition.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the leafset of the related condition tree.
|
* Gets the leafset of the related condition tree.
|
||||||
*
|
*
|
||||||
* @return All the leaf conditions as a set.
|
* @return All the leaf conditions as a set.
|
||||||
*/
|
*/
|
||||||
public Set<ConditionsTreeNode> getLeafSet() {
|
public Set<ConditionsTreeNode> getLeafSet() {
|
||||||
return mLeafSet;
|
return mLeafSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// Public accesor methods
|
// Public accesor methods
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
/**
|
/**
|
||||||
* TODO THIS HAS TO GO!!!!
|
* TODO THIS HAS TO GO!!!!
|
||||||
* very dirty fix for remotesearch support atm
|
* very dirty fix for remotesearch support atm
|
||||||
*/
|
*/
|
||||||
public String getRemoteSearchArguments() {
|
public String getRemoteSearchArguments() {
|
||||||
for (ConditionsTreeNode node : getLeafSet()) {
|
for (ConditionsTreeNode node : getLeafSet()) {
|
||||||
if (node.getCondition().field == SEARCHFIELD.SUBJECT
|
if (node.getCondition().field == SEARCHFIELD.SUBJECT
|
||||||
|| node.getCondition().field == SEARCHFIELD.SENDER ) {
|
|| node.getCondition().field == SEARCHFIELD.SENDER ) {
|
||||||
return node.getCondition().value;
|
return node.getCondition().value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the saved search.
|
* Returns the name of the saved search.
|
||||||
*
|
*
|
||||||
@ -314,22 +314,22 @@ public class LocalSearch implements SearchSpecification {
|
|||||||
public String getName() {
|
public String getName() {
|
||||||
return (mName == null ? "" : mName);
|
return (mName == null ? "" : mName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this search was hard coded and shipped with K-9
|
* Checks if this search was hard coded and shipped with K-9
|
||||||
*
|
*
|
||||||
* @return True is search was shipped with K-9
|
* @return True is search was shipped with K-9
|
||||||
*/
|
*/
|
||||||
public boolean isPredefined() {
|
public boolean isPredefined() {
|
||||||
return mPredefined;
|
return mPredefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all the account uuids that this search will try to
|
* Returns all the account uuids that this search will try to
|
||||||
* match against.
|
* match against.
|
||||||
*
|
*
|
||||||
* @return Array of account uuids.
|
* @return Array of account uuids.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String[] getAccountUuids() {
|
public String[] getAccountUuids() {
|
||||||
if (mAccountUuids.size() == 0) {
|
if (mAccountUuids.size() == 0) {
|
||||||
@ -346,43 +346,43 @@ public class LocalSearch implements SearchSpecification {
|
|||||||
*
|
*
|
||||||
* @return The root node of the related conditions tree.
|
* @return The root node of the related conditions tree.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ConditionsTreeNode getConditions() {
|
public ConditionsTreeNode getConditions() {
|
||||||
return mConditions;
|
return mConditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
// Parcelable
|
|
||||||
///////////////////////////////////////////////////////////////
|
|
||||||
@Override
|
|
||||||
public int describeContents() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
///////////////////////////////////////////////////////////////
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
// Parcelable
|
||||||
dest.writeString(mName);
|
///////////////////////////////////////////////////////////////
|
||||||
dest.writeByte((byte) (mPredefined ? 1 : 0));
|
@Override
|
||||||
dest.writeStringList(new ArrayList<String>(mAccountUuids));
|
public int describeContents() {
|
||||||
dest.writeParcelable(mConditions, flags);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<LocalSearch> CREATOR
|
@Override
|
||||||
= new Parcelable.Creator<LocalSearch>() {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
public LocalSearch createFromParcel(Parcel in) {
|
dest.writeString(mName);
|
||||||
return new LocalSearch(in);
|
dest.writeByte((byte) (mPredefined ? 1 : 0));
|
||||||
}
|
dest.writeStringList(new ArrayList<String>(mAccountUuids));
|
||||||
|
dest.writeParcelable(mConditions, flags);
|
||||||
public LocalSearch[] newArray(int size) {
|
}
|
||||||
return new LocalSearch[size];
|
|
||||||
}
|
public static final Parcelable.Creator<LocalSearch> CREATOR
|
||||||
};
|
= new Parcelable.Creator<LocalSearch>() {
|
||||||
|
public LocalSearch createFromParcel(Parcel in) {
|
||||||
public LocalSearch(Parcel in) {
|
return new LocalSearch(in);
|
||||||
mName = in.readString();
|
}
|
||||||
mPredefined = in.readByte() == 1;
|
|
||||||
mAccountUuids.addAll(in.createStringArrayList());
|
public LocalSearch[] newArray(int size) {
|
||||||
mConditions = in.readParcelable(LocalSearch.class.getClassLoader());
|
return new LocalSearch[size];
|
||||||
mLeafSet = mConditions.getLeafSet();
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
public LocalSearch(Parcel in) {
|
||||||
|
mName = in.readString();
|
||||||
|
mPredefined = in.readByte() == 1;
|
||||||
|
mAccountUuids.addAll(in.createStringArrayList());
|
||||||
|
mConditions = in.readParcelable(LocalSearch.class.getClassLoader());
|
||||||
|
mLeafSet = mConditions.getLeafSet();
|
||||||
|
}
|
||||||
}
|
}
|
@ -14,36 +14,36 @@ import com.fsck.k9.R;
|
|||||||
public class SearchAccount implements BaseAccount {
|
public class SearchAccount implements BaseAccount {
|
||||||
|
|
||||||
// create the all messages search ( all accounts is default when none specified )
|
// create the all messages search ( all accounts is default when none specified )
|
||||||
public static SearchAccount createAllMessagesAccount(Context context) {
|
public static SearchAccount createAllMessagesAccount(Context context) {
|
||||||
String name = context.getString(R.string.search_all_messages_title);
|
String name = context.getString(R.string.search_all_messages_title);
|
||||||
LocalSearch tmpSearch = new LocalSearch(name);
|
LocalSearch tmpSearch = new LocalSearch(name);
|
||||||
return new SearchAccount(tmpSearch, name,
|
return new SearchAccount(tmpSearch, name,
|
||||||
context.getString(R.string.search_all_messages_detail));
|
context.getString(R.string.search_all_messages_detail));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// create the unified inbox meta account ( all accounts is default when none specified )
|
|
||||||
public static SearchAccount createUnifiedInboxAccount(Context context) {
|
// create the unified inbox meta account ( all accounts is default when none specified )
|
||||||
|
public static SearchAccount createUnifiedInboxAccount(Context context) {
|
||||||
String name = context.getString(R.string.integrated_inbox_title);
|
String name = context.getString(R.string.integrated_inbox_title);
|
||||||
LocalSearch tmpSearch = new LocalSearch(name);
|
LocalSearch tmpSearch = new LocalSearch(name);
|
||||||
tmpSearch.addAllowedFolder(SearchSpecification.GENERIC_INBOX_NAME);
|
tmpSearch.addAllowedFolder(SearchSpecification.GENERIC_INBOX_NAME);
|
||||||
return new SearchAccount(tmpSearch, name,
|
return new SearchAccount(tmpSearch, name,
|
||||||
context.getString(R.string.integrated_inbox_detail));
|
context.getString(R.string.integrated_inbox_detail));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String mEmail = null;
|
private String mEmail = null;
|
||||||
private String mDescription = null;
|
private String mDescription = null;
|
||||||
private LocalSearch mSearch = null;
|
private LocalSearch mSearch = null;
|
||||||
private String mFakeUuid = null;
|
private String mFakeUuid = null;
|
||||||
|
|
||||||
public SearchAccount(LocalSearch search, String description, String email) throws IllegalArgumentException{
|
public SearchAccount(LocalSearch search, String description, String email) throws IllegalArgumentException{
|
||||||
if (search == null) {
|
if (search == null) {
|
||||||
throw new IllegalArgumentException("Provided LocalSearch was null");
|
throw new IllegalArgumentException("Provided LocalSearch was null");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mSearch = search;
|
this.mSearch = search;
|
||||||
this.mDescription = description;
|
this.mDescription = description;
|
||||||
this.mEmail = email;
|
this.mEmail = email;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -55,33 +55,33 @@ public class SearchAccount implements BaseAccount {
|
|||||||
public synchronized void setEmail(String email) {
|
public synchronized void setEmail(String email) {
|
||||||
this.mEmail = email;
|
this.mEmail = email;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return mDescription;
|
return mDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDescription(String description) {
|
public void setDescription(String description) {
|
||||||
this.mDescription = description;
|
this.mDescription = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalSearch getRelatedSearch() {
|
public LocalSearch getRelatedSearch() {
|
||||||
return mSearch;
|
return mSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
/*
|
/*
|
||||||
* This will only be used when accessed as an Account. If that
|
* This will only be used when accessed as an Account. If that
|
||||||
* is the case we don't want to return the uuid of a real account since
|
* is the case we don't want to return the uuid of a real account since
|
||||||
* this is posing as a fake meta-account. If this object is accesed as
|
* this is posing as a fake meta-account. If this object is accesed as
|
||||||
* a Search then methods from LocalSearch will be called which do handle
|
* a Search then methods from LocalSearch will be called which do handle
|
||||||
* things nice.
|
* things nice.
|
||||||
*/
|
*/
|
||||||
public String getUuid() {
|
public String getUuid() {
|
||||||
if (mFakeUuid == null){
|
if (mFakeUuid == null){
|
||||||
mFakeUuid = UUID.randomUUID().toString();
|
mFakeUuid = UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
return mFakeUuid;
|
return mFakeUuid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,79 +4,79 @@ import android.os.Parcel;
|
|||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
public interface SearchSpecification extends Parcelable {
|
public interface SearchSpecification extends Parcelable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the uuids of accounts this search acts on.
|
* Get all the uuids of accounts this search acts on.
|
||||||
* @return Array of uuids.
|
* @return Array of uuids.
|
||||||
*/
|
*/
|
||||||
public String[] getAccountUuids();
|
public String[] getAccountUuids();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the search's name if it was named.
|
* Returns the search's name if it was named.
|
||||||
* @return Name of the search.
|
* @return Name of the search.
|
||||||
*/
|
*/
|
||||||
public String getName();
|
public String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the root node of the condition tree accompanying
|
* Returns the root node of the condition tree accompanying
|
||||||
* the search.
|
* the search.
|
||||||
*
|
*
|
||||||
* @return Root node of conditions tree.
|
* @return Root node of conditions tree.
|
||||||
*/
|
*/
|
||||||
public ConditionsTreeNode getConditions();
|
public ConditionsTreeNode getConditions();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some meta names for certain conditions.
|
* Some meta names for certain conditions.
|
||||||
*/
|
*/
|
||||||
public static final String ALL_ACCOUNTS = "allAccounts";
|
public static final String ALL_ACCOUNTS = "allAccounts";
|
||||||
public static final String GENERIC_INBOX_NAME = "genericInboxName";
|
public static final String GENERIC_INBOX_NAME = "genericInboxName";
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// ATTRIBUTE enum
|
// ATTRIBUTE enum
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
public enum ATTRIBUTE {
|
public enum ATTRIBUTE {
|
||||||
CONTAINS(false), EQUALS(false), STARTSWITH(false), ENDSWITH(false),
|
CONTAINS(false), EQUALS(false), STARTSWITH(false), ENDSWITH(false),
|
||||||
NOT_CONTAINS(true), NOT_EQUALS(true), NOT_STARTSWITH(true), NOT_ENDSWITH(true);
|
NOT_CONTAINS(true), NOT_EQUALS(true), NOT_STARTSWITH(true), NOT_ENDSWITH(true);
|
||||||
|
|
||||||
private boolean mNegation;
|
private boolean mNegation;
|
||||||
|
|
||||||
private ATTRIBUTE(boolean negation) {
|
private ATTRIBUTE(boolean negation) {
|
||||||
this.mNegation = negation;
|
this.mNegation = negation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String formQuery(String value) {
|
public String formQuery(String value) {
|
||||||
String queryPart = "";
|
String queryPart = "";
|
||||||
|
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case NOT_CONTAINS:
|
case NOT_CONTAINS:
|
||||||
case CONTAINS:
|
case CONTAINS:
|
||||||
queryPart = "'%"+value+"%'";
|
queryPart = "'%"+value+"%'";
|
||||||
break;
|
break;
|
||||||
case NOT_EQUALS:
|
case NOT_EQUALS:
|
||||||
case EQUALS:
|
case EQUALS:
|
||||||
queryPart = "'"+value+"'";
|
queryPart = "'"+value+"'";
|
||||||
break;
|
break;
|
||||||
case NOT_STARTSWITH:
|
case NOT_STARTSWITH:
|
||||||
case STARTSWITH:
|
case STARTSWITH:
|
||||||
queryPart = "'%"+value+"'";
|
queryPart = "'%"+value+"'";
|
||||||
break;
|
break;
|
||||||
case NOT_ENDSWITH:
|
case NOT_ENDSWITH:
|
||||||
case ENDSWITH:
|
case ENDSWITH:
|
||||||
queryPart = "'"+value+"%'";
|
queryPart = "'"+value+"%'";
|
||||||
break;
|
break;
|
||||||
default: queryPart = "'"+value+"'";
|
default: queryPart = "'"+value+"'";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (mNegation ? " NOT LIKE " : " LIKE ") + queryPart;
|
return (mNegation ? " NOT LIKE " : " LIKE ") + queryPart;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// SEARCHFIELD enum
|
// SEARCHFIELD enum
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
/*
|
/*
|
||||||
* Using an enum in order to have more robust code. Users ( & coders )
|
* Using an enum in order to have more robust code. Users ( & coders )
|
||||||
* are prevented from passing illegal fields. No database overhead
|
* are prevented from passing illegal fields. No database overhead
|
||||||
* when invalid fields passed.
|
* when invalid fields passed.
|
||||||
*
|
*
|
||||||
* By result, only the fields in here are searchable.
|
* By result, only the fields in here are searchable.
|
||||||
@ -84,7 +84,7 @@ public interface SearchSpecification extends Parcelable {
|
|||||||
* Fields not in here at this moment ( and by effect not searchable ):
|
* Fields not in here at this moment ( and by effect not searchable ):
|
||||||
* id, html_content, internal_date, message_id,
|
* id, html_content, internal_date, message_id,
|
||||||
* preview, mime_type
|
* preview, mime_type
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public enum SEARCHFIELD {
|
public enum SEARCHFIELD {
|
||||||
SUBJECT("subject"), DATE("date"), UID("uid"), FLAG("flags"),
|
SUBJECT("subject"), DATE("date"), UID("uid"), FLAG("flags"),
|
||||||
@ -93,7 +93,7 @@ public interface SearchSpecification extends Parcelable {
|
|||||||
ATTACHMENT_COUNT("attachment_count"), DELETED("deleted"), THREAD_ROOT("thread_root");
|
ATTACHMENT_COUNT("attachment_count"), DELETED("deleted"), THREAD_ROOT("thread_root");
|
||||||
|
|
||||||
private String dbName;
|
private String dbName;
|
||||||
|
|
||||||
private SEARCHFIELD(String dbName) {
|
private SEARCHFIELD(String dbName) {
|
||||||
this.dbName = dbName;
|
this.dbName = dbName;
|
||||||
}
|
}
|
||||||
@ -102,25 +102,25 @@ public interface SearchSpecification extends Parcelable {
|
|||||||
return dbName;
|
return dbName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
// SearchCondition class
|
// SearchCondition class
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
/**
|
/**
|
||||||
* This class represents 1 value for a certain search field. One
|
* This class represents 1 value for a certain search field. One
|
||||||
* value consists of three things:
|
* value consists of three things:
|
||||||
* an attribute: equals, starts with, contains,...
|
* an attribute: equals, starts with, contains,...
|
||||||
* a searchfield: date, flags, sender, subject,...
|
* a searchfield: date, flags, sender, subject,...
|
||||||
* a value: "apple", "jesse",..
|
* a value: "apple", "jesse",..
|
||||||
*
|
*
|
||||||
* @author dzan
|
* @author dzan
|
||||||
*/
|
*/
|
||||||
public class SearchCondition implements Parcelable{
|
public class SearchCondition implements Parcelable{
|
||||||
public String value;
|
public String value;
|
||||||
public ATTRIBUTE attribute;
|
public ATTRIBUTE attribute;
|
||||||
public SEARCHFIELD field;
|
public SEARCHFIELD field;
|
||||||
|
|
||||||
public SearchCondition(SEARCHFIELD field, ATTRIBUTE attribute, String value) {
|
public SearchCondition(SEARCHFIELD field, ATTRIBUTE attribute, String value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.attribute = attribute;
|
this.attribute = attribute;
|
||||||
@ -128,26 +128,26 @@ public interface SearchSpecification extends Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SearchCondition(Parcel in) {
|
private SearchCondition(Parcel in) {
|
||||||
this.value = in.readString();
|
this.value = in.readString();
|
||||||
this.attribute = ATTRIBUTE.values()[in.readInt()];
|
this.attribute = ATTRIBUTE.values()[in.readInt()];
|
||||||
this.field = SEARCHFIELD.values()[in.readInt()];
|
this.field = SEARCHFIELD.values()[in.readInt()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toHumanString() {
|
public String toHumanString() {
|
||||||
return field.toString() + attribute.toString();
|
return field.toString() + attribute.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return field.getDatabaseName() + attribute.formQuery(value);
|
return field.getDatabaseName() + attribute.formQuery(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (o instanceof SearchCondition) {
|
if (o instanceof SearchCondition) {
|
||||||
SearchCondition tmp = (SearchCondition) o;
|
SearchCondition tmp = (SearchCondition) o;
|
||||||
if (tmp.attribute == attribute
|
if (tmp.attribute == attribute
|
||||||
&& tmp.value.equals(value)
|
&& tmp.value.equals(value)
|
||||||
&& tmp.field == field) {
|
&& tmp.field == field) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -158,27 +158,27 @@ public interface SearchSpecification extends Parcelable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
dest.writeString(value);
|
dest.writeString(value);
|
||||||
dest.writeInt(attribute.ordinal());
|
dest.writeInt(attribute.ordinal());
|
||||||
dest.writeInt(field.ordinal());
|
dest.writeInt(field.ordinal());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<SearchCondition> CREATOR
|
public static final Parcelable.Creator<SearchCondition> CREATOR
|
||||||
= new Parcelable.Creator<SearchCondition>() {
|
= new Parcelable.Creator<SearchCondition>() {
|
||||||
public SearchCondition createFromParcel(Parcel in) {
|
public SearchCondition createFromParcel(Parcel in) {
|
||||||
return new SearchCondition(in);
|
return new SearchCondition(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SearchCondition[] newArray(int size) {
|
public SearchCondition[] newArray(int size) {
|
||||||
return new SearchCondition[size];
|
return new SearchCondition[size];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user