1/*
2 * Copyright (C) 2012 Google Inc.
3 * Licensed to The Android Open Source Project.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mail.ui;
19
20import android.content.Context;
21import android.content.DialogInterface;
22import android.database.Cursor;
23import android.net.Uri;
24
25import com.android.mail.R;
26import com.android.mail.providers.Account;
27import com.android.mail.providers.Conversation;
28import com.android.mail.providers.Folder;
29import com.android.mail.providers.UIProvider;
30import com.android.mail.providers.UIProvider.FolderType;
31import com.android.mail.ui.FolderSelectorAdapter.FolderRow;
32import com.android.mail.utils.Utils;
33import com.google.common.collect.ImmutableSet;
34
35import java.util.Arrays;
36import java.util.Collection;
37import java.util.HashMap;
38import java.util.HashSet;
39import java.util.List;
40
41/**
42 * Displays a folder selection dialog for the conversation provided. It allows
43 * the user to mark folders to assign that conversation to.
44 */
45public class MultiFoldersSelectionDialog extends FolderSelectionDialog {
46    private final boolean mSingle;
47    private final HashMap<Uri, FolderOperation> mOperations;
48
49    /**
50     * Create a new {@link MultiFoldersSelectionDialog}. It is displayed when
51     * the {@link #show()} method is called.
52     * @param context
53     * @param account the current account
54     * @param updater
55     * @param target conversations that are impacted
56     * @param isBatch whether the dialog is shown during Contextual Action Bar
57     *            (CAB) mode
58     * @param currentFolder the current folder that the
59     *            {@link FolderListFragment} is showing
60     */
61    public MultiFoldersSelectionDialog(final Context context, final Account account,
62            final ConversationUpdater updater, final Collection<Conversation> target,
63            final boolean isBatch, final Folder currentFolder) {
64        super(context, account, updater, target, isBatch, currentFolder);
65        mSingle = !account
66                .supportsCapability(UIProvider.AccountCapabilities.MULTIPLE_FOLDERS_PER_CONV);
67        mOperations = new HashMap<Uri, FolderOperation>();
68
69        mBuilder.setTitle(R.string.change_folders_selection_dialog_title);
70        mBuilder.setPositiveButton(R.string.ok, this);
71    }
72
73    @Override
74    protected void updateAdapterInBackground(Context context) {
75        Cursor foldersCursor = null;
76        try {
77            foldersCursor = context.getContentResolver().query(
78                    !Utils.isEmpty(mAccount.fullFolderListUri) ? mAccount.fullFolderListUri
79                            : mAccount.folderListUri, UIProvider.FOLDERS_PROJECTION, null, null,
80                            null);
81            /** All the folders that this conversations is assigned to. */
82            final HashSet<String> checked = new HashSet<String>();
83            for (final Conversation conversation : mTarget) {
84                final List<Folder> rawFolders = conversation.getRawFolders();
85                if (rawFolders != null && rawFolders.size() > 0) {
86                    // Parse the raw folders and get all the uris.
87                    checked.addAll(Arrays.asList(Folder.getUriArray(rawFolders)));
88                } else {
89                    // There are no folders for this conversation, so it must
90                    // belong to the folder we are currently looking at.
91                    checked.add(mCurrentFolder.folderUri.fullUri.toString());
92                }
93            }
94            // TODO(mindyp) : bring this back in UR8 when Email providers
95            // will have divided folder sections.
96            /* final String[] headers = mContext.getResources()
97             .getStringArray(R.array.moveto_folder_sections);
98             // Currently, the number of adapters are assumed to match the
99             // number of headers in the string array.
100             mAdapter.addSection(new SystemFolderSelectorAdapter(mContext,
101             foldersCursor, checked, R.layout.multi_folders_view, null));
102
103            // TODO(mindyp): we currently do not support frequently moved to
104            // folders, at headers[1]; need to define what that means.*/
105            mAdapter.addSection(new AddableFolderSelectorAdapter(context,
106                    AddableFolderSelectorAdapter.filterFolders(foldersCursor,
107                            ImmutableSet.of(FolderType.INBOX_SECTION)), checked,
108                    R.layout.multi_folders_view, null));
109            mBuilder.setAdapter(mAdapter, MultiFoldersSelectionDialog.this);
110        } finally {
111            if (foldersCursor != null) {
112                foldersCursor.close();
113            }
114        }
115    }
116
117    @Override
118    protected void onListItemClick(int position) {
119        final Object item = mAdapter.getItem(position);
120        if (item instanceof FolderRow) {
121            update((FolderRow) item);
122        }
123    }
124
125    /**
126     * Call this to update the state of folders as a result of them being
127     * selected / de-selected.
128     *
129     * @param row The item being updated.
130     */
131    private final void update(FolderSelectorAdapter.FolderRow row) {
132        final boolean add = !row.isPresent();
133        if (mSingle) {
134            if (!add) {
135                // This would remove the check on a single radio button, so just
136                // return.
137                return;
138            }
139            // Clear any other checked items.
140            for (int i = 0, size = mAdapter.getCount(); i < size; i++) {
141                final Object item = mAdapter.getItem(i);
142                if (item instanceof FolderRow) {
143                   ((FolderRow)item).setIsPresent(false);
144                   final Folder folder = ((FolderRow)item).getFolder();
145                   mOperations.put(folder.folderUri.fullUri,
146                           new FolderOperation(folder, false));
147                }
148            }
149        }
150        row.setIsPresent(add);
151        mAdapter.notifyDataSetChanged();
152        final Folder folder = row.getFolder();
153        mOperations.put(folder.folderUri.fullUri, new FolderOperation(folder, add));
154    }
155
156    @Override
157    public void onClick(DialogInterface dialog, int which) {
158        switch (which) {
159            case DialogInterface.BUTTON_POSITIVE:
160                if (mUpdater != null) {
161                    mUpdater.assignFolder(mOperations.values(), mTarget, mBatch,
162                            true /* showUndo */, false /* isMoveTo */);
163                }
164                break;
165            case DialogInterface.BUTTON_NEGATIVE:
166                break;
167            default:
168                break;
169        }
170    }
171}
172