Removed unnecessary actions
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / preview / PreviewTextFragment.java
1 package com.owncloud.android.ui.preview;
2
3 import android.accounts.Account;
4 import android.annotation.SuppressLint;
5 import android.content.Context;
6 import android.graphics.Paint;
7 import android.graphics.Rect;
8 import android.os.AsyncTask;
9 import android.os.Bundle;
10 import android.support.v4.app.Fragment;
11 import android.support.v4.app.FragmentManager;
12 import android.support.v4.app.FragmentTransaction;
13 import android.util.DisplayMetrics;
14 import android.view.LayoutInflater;
15 import android.view.View;
16 import android.view.ViewGroup;
17 import android.widget.BaseAdapter;
18 import android.widget.ListView;
19 import android.widget.TextView;
20
21 import com.actionbarsherlock.view.Menu;
22 import com.actionbarsherlock.view.MenuInflater;
23 import com.actionbarsherlock.view.MenuItem;
24 import com.owncloud.android.R;
25 import com.owncloud.android.datamodel.OCFile;
26 import com.owncloud.android.files.FileMenuFilter;
27 import com.owncloud.android.lib.common.utils.Log_OC;
28 import com.owncloud.android.ui.activity.FileDisplayActivity;
29 import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
30 import com.owncloud.android.ui.dialog.LoadingDialog;
31 import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
32 import com.owncloud.android.ui.fragment.FileFragment;
33
34 import java.io.BufferedWriter;
35 import java.io.FileInputStream;
36 import java.io.IOException;
37 import java.io.StringWriter;
38 import java.util.ArrayList;
39 import java.util.LinkedList;
40 import java.util.List;
41 import java.util.Queue;
42 import java.util.Scanner;
43
44 public class PreviewTextFragment extends FileFragment {
45 private static final String EXTRA_FILE = "FILE";
46 private static final String EXTRA_ACCOUNT = "ACCOUNT";
47 private static final String TAG = PreviewTextFragment.class.getSimpleName();
48
49 private Account mAccount;
50 private ListView mTextPreviewList;
51
52 /**
53 * Creates an empty fragment for previews.
54 * <p/>
55 * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically
56 * (for instance, when the device is turned a aside).
57 * <p/>
58 * DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful
59 * construction
60 */
61 public PreviewTextFragment() {
62 super();
63 mAccount = null;
64 }
65
66 /**
67 * {@inheritDoc}
68 */
69 @Override
70 public View onCreateView(LayoutInflater inflater, ViewGroup container,
71 Bundle savedInstanceState) {
72 super.onCreateView(inflater, container, savedInstanceState);
73 Log_OC.e(TAG, "onCreateView");
74
75
76 View ret = inflater.inflate(R.layout.text_file_preview, container, false);
77
78 mTextPreviewList = (ListView) ret.findViewById(R.id.text_preview_list);
79 mTextPreviewList.setAdapter(new TextLineAdapter());
80
81 return ret;
82 }
83
84 /**
85 * {@inheritDoc}
86 */
87 @Override
88 public void onCreate(Bundle savedInstanceState) {
89 super.onCreate(savedInstanceState);
90
91 OCFile file = getFile();
92
93 Bundle args = getArguments();
94
95 if (file == null)
96 file = args.getParcelable(FileDisplayActivity.EXTRA_FILE);
97
98 if (mAccount == null)
99 mAccount = args.getParcelable(FileDisplayActivity.EXTRA_ACCOUNT);
100
101
102 if (savedInstanceState == null) {
103 if (file == null) {
104 throw new IllegalStateException("Instanced with a NULL OCFile");
105 }
106 if (mAccount == null) {
107 throw new IllegalStateException("Instanced with a NULL ownCloud Account");
108 }
109 } else {
110 file = savedInstanceState.getParcelable(EXTRA_FILE);
111 mAccount = savedInstanceState.getParcelable(EXTRA_ACCOUNT);
112 }
113 setFile(file);
114 setHasOptionsMenu(true);
115 }
116
117 /**
118 * {@inheritDoc}
119 */
120 @Override
121 public void onSaveInstanceState(Bundle outState) {
122 super.onSaveInstanceState(outState);
123 outState.putParcelable(PreviewImageFragment.EXTRA_FILE, getFile());
124 outState.putParcelable(PreviewImageFragment.EXTRA_ACCOUNT, mAccount);
125 }
126
127 @Override
128 public void onStart() {
129 super.onStart();
130 Log_OC.e(TAG, "onStart");
131 }
132
133 private void loadAndShowTextPreview() {
134 new TextLoadAsyncTask().execute(getFile().getStoragePath());
135 }
136
137 /**
138 * Reads the file to preview and shows its contents. Too critical to be anonymous.
139 */
140 private class TextLoadAsyncTask extends AsyncTask<Object, StringWriter, Void> {
141 private int TEXTVIEW_WIDTH;
142 private float TEXTVIEW_SIZE;
143 private final Queue<Character> accumulatedText = new LinkedList<Character>();
144 private final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
145 private final Rect bounds = new Rect();
146 private final Paint paint = new Paint();
147
148 @SuppressLint("InflateParams")
149 @Override
150 protected void onPreExecute() {
151 ((TextLineAdapter) mTextPreviewList.getAdapter()).clear();
152 DisplayMetrics displaymetrics = new DisplayMetrics();
153 getActivity().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
154 TEXTVIEW_WIDTH = displaymetrics.widthPixels;
155 TEXTVIEW_SIZE = ((TextView) ((LayoutInflater) getActivity().getApplicationContext()
156 .getSystemService(Context.LAYOUT_INFLATER_SERVICE))
157 .inflate(
158 R.layout.text_file_preview_list_item, null)).getTextSize();
159 showLoadingDialog();
160 paint.setTextSize(TEXTVIEW_SIZE);
161 }
162
163 @Override
164 protected Void doInBackground(java.lang.Object... params) {
165 if (params.length != 1)
166 throw new IllegalArgumentException("The parameter to " + TextLoadAsyncTask.class.getName() + " must be the file location only");
167 final String location = (String) params[0];
168
169 FileInputStream inputStream = null;
170 Scanner sc = null;
171 try {
172 inputStream = new FileInputStream(location);
173 sc = new Scanner(inputStream);
174 while (sc.hasNextLine()) {
175 StringWriter target = new StringWriter();
176 BufferedWriter bufferedWriter = new BufferedWriter(target);
177 if (sc.hasNextLine())
178 bufferedWriter.write(sc.nextLine());
179 bufferedWriter.close();
180 publishProgress(target);
181 }
182 IOException exc = sc.ioException();
183 if (exc != null) throw exc;
184 } catch (IOException e) {
185 finish();
186 } finally {
187 if (inputStream != null) {
188 try {
189 inputStream.close();
190 } catch (IOException e) {
191 finish();
192 }
193 }
194 if (sc != null) {
195 sc.close();
196 }
197 }
198 //Add the remaining text, if any
199 while (!accumulatedText.isEmpty()) {
200 addLine();
201 }
202 return null;
203 }
204
205 @Override
206 protected void onProgressUpdate(StringWriter... values) {
207 super.onProgressUpdate(values);
208 final char[] newTextAsCharArray = values[0].toString().toCharArray();
209 for (char c : newTextAsCharArray) {
210 accumulatedText.add(c);
211 }
212 addLine();
213 }
214
215 private synchronized void addLine() {
216 StringBuilder textForThisLine = new StringBuilder();
217 do {
218 Character polled = accumulatedText.poll();
219 textForThisLine.append(polled);
220 }
221 while (!isTooLarge(textForThisLine.toString()) && !accumulatedText.isEmpty());
222 String line = textForThisLine.toString();
223 ((TextLineAdapter) mTextPreviewList.getAdapter()).add(line.contentEquals("null") ? "" : line);
224 }
225
226 private boolean isTooLarge(String text) {
227 paint.getTextBounds(text, 0, text.length(), bounds);
228 int lineWidth = (int) Math.ceil(bounds.width());
229 return lineWidth / TEXTVIEW_WIDTH > 1;
230 }
231
232 @Override
233 protected void onPostExecute(Void aVoid) {
234 super.onPostExecute(aVoid);
235 mTextPreviewList.setVisibility(View.VISIBLE);
236 dismissLoadingDialog();
237 }
238
239 /**
240 * Show loading dialog
241 */
242 public void showLoadingDialog() {
243 // Construct dialog
244 LoadingDialog loading = new LoadingDialog(getResources().getString(R.string.wait_a_moment));
245 FragmentManager fm = getActivity().getSupportFragmentManager();
246 FragmentTransaction ft = fm.beginTransaction();
247 loading.show(ft, DIALOG_WAIT_TAG);
248 }
249
250 /**
251 * Dismiss loading dialog
252 */
253 public void dismissLoadingDialog() {
254 Fragment frag = getActivity().getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG);
255 if (frag != null) {
256 LoadingDialog loading = (LoadingDialog) frag;
257 loading.dismiss();
258 }
259 }
260 }
261
262 private class TextLineAdapter extends BaseAdapter {
263 private static final int LIST_ITEM_LAYOUT = R.layout.text_file_preview_list_item;
264 private final List<String> items = new ArrayList<String>();
265
266 private void add(String line) {
267 items.add(line);
268 getActivity().runOnUiThread(new Runnable() {
269 @Override
270 public void run() {
271 notifyDataSetChanged();
272 }
273 });
274 }
275
276 private void clear() {
277 items.clear();
278 getActivity().runOnUiThread(new Runnable() {
279 @Override
280 public void run() {
281 notifyDataSetChanged();
282 }
283 });
284 }
285
286 @Override
287 public int getCount() {
288 return items.size();
289 }
290
291 @Override
292 public String getItem(int position) {
293 if (position >= items.size())
294 throw new IllegalArgumentException();
295 return items.get(position);
296 }
297
298 @Override
299 public long getItemId(int position) {
300 return position;
301 }
302
303 @Override
304 public View getView(int position, View convertView, ViewGroup parent) {
305 ViewHolder viewHolder;
306 if (convertView == null) {
307 convertView =
308 ((LayoutInflater) getActivity().getApplicationContext()
309 .getSystemService(Context.LAYOUT_INFLATER_SERVICE))
310 .inflate(
311 LIST_ITEM_LAYOUT, null);
312 viewHolder = new ViewHolder();
313 viewHolder.setLineView((TextView) convertView.findViewById(R.id.text_preview));
314 convertView.setTag(viewHolder);
315 } else {
316 viewHolder = (ViewHolder) convertView.getTag();
317 }
318
319 viewHolder.getLineView().setText(items.get(position));
320
321 return convertView;
322 }
323 }
324
325 private static class ViewHolder {
326 private TextView lineView;
327
328 private ViewHolder() {
329 }
330
331 public TextView getLineView() {
332 return lineView;
333 }
334
335 public void setLineView(TextView lineView) {
336 this.lineView = lineView;
337 }
338 }
339
340 /**
341 * {@inheritDoc}
342 */
343 @Override
344 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
345 super.onCreateOptionsMenu(menu, inflater);
346 inflater.inflate(R.menu.file_actions_menu, menu);
347 }
348
349 /**
350 * {@inheritDoc}
351 */
352 @Override
353 public void onPrepareOptionsMenu(Menu menu) {
354 super.onPrepareOptionsMenu(menu);
355
356 if (mContainerActivity.getStorageManager() != null) {
357 FileMenuFilter mf = new FileMenuFilter(
358 getFile(),
359 mContainerActivity.getStorageManager().getAccount(),
360 mContainerActivity,
361 getSherlockActivity()
362 );
363 mf.filter(menu);
364 }
365
366 // additional restriction for this fragment
367 MenuItem item = menu.findItem(R.id.action_rename_file);
368 if (item != null) {
369 item.setVisible(false);
370 item.setEnabled(false);
371 }
372
373 // additional restriction for this fragment
374 item = menu.findItem(R.id.action_move);
375 if (item != null) {
376 item.setVisible(false);
377 item.setEnabled(false);
378 }
379
380 // this one doesn't make sense since the file has to be down in order to be previewed
381 item = menu.findItem(R.id.action_download_file);
382 if (item != null) {
383 item.setVisible(false);
384 item.setEnabled(false);
385 }
386
387 item = menu.findItem(R.id.action_settings);
388 if (item != null) {
389 item.setVisible(false);
390 item.setEnabled(false);
391 }
392
393 item = menu.findItem(R.id.action_logger);
394 if (item != null) {
395 item.setVisible(false);
396 item.setEnabled(false);
397 }
398
399 item = menu.findItem(R.id.action_sync_file);
400 if (item != null) {
401 item.setVisible(false);
402 item.setEnabled(false);
403 }
404
405 item = menu.findItem(R.id.action_sync_account);
406 if (item != null) {
407 item.setVisible(false);
408 item.setEnabled(false);
409 }
410 }
411
412 /**
413 * {@inheritDoc}
414 */
415 @Override
416 public boolean onOptionsItemSelected(MenuItem item) {
417 switch (item.getItemId()) {
418 case R.id.action_share_file: {
419 mContainerActivity.getFileOperationsHelper().shareFileWithLink(getFile());
420 return true;
421 }
422 case R.id.action_unshare_file: {
423 mContainerActivity.getFileOperationsHelper().unshareFileWithLink(getFile());
424 return true;
425 }
426 case R.id.action_open_file_with: {
427 openFile();
428 return true;
429 }
430 case R.id.action_remove_file: {
431 RemoveFileDialogFragment dialog = RemoveFileDialogFragment.newInstance(getFile());
432 dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
433 return true;
434 }
435 case R.id.action_see_details: {
436 seeDetails();
437 return true;
438 }
439 case R.id.action_send_file: {
440 sendFile();
441 return true;
442 }
443 case R.id.action_sync_file: {
444 mContainerActivity.getFileOperationsHelper().syncFile(getFile());
445 return true;
446 }
447
448 default:
449 return false;
450 }
451 }
452
453 /**
454 * Update the file of the fragment with file value
455 *
456 * @param file The new file to set
457 */
458 public void updateFile(OCFile file) {
459 setFile(file);
460 }
461
462 private void sendFile() {
463 mContainerActivity.getFileOperationsHelper().sendDownloadedFile(getFile());
464 }
465
466 private void seeDetails() {
467 mContainerActivity.showDetails(getFile());
468 }
469
470 @Override
471 public void onPause() {
472 Log_OC.e(TAG, "onPause");
473 super.onPause();
474 }
475
476 @Override
477 public void onResume() {
478 super.onResume();
479 Log_OC.e(TAG, "onResume");
480
481 loadAndShowTextPreview();
482 }
483
484 @Override
485 public void onDestroy() {
486 Log_OC.e(TAG, "onDestroy");
487 super.onDestroy();
488 }
489
490 @Override
491 public void onStop() {
492 super.onStop();
493 Log_OC.e(TAG, "onStop");
494 }
495
496 /**
497 * Opens the previewed file with an external application.
498 */
499 private void openFile() {
500 mContainerActivity.getFileOperationsHelper().openFile(getFile());
501 finish();
502 }
503
504 /**
505 * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewTextFragment} to be previewed.
506 *
507 * @param file File to test if can be previewed.
508 * @return 'True' if the file can be handled by the fragment.
509 */
510 public static boolean canBePreviewed(OCFile file) {
511 return (file != null && file.isDown() && file.isText());
512 }
513
514 /**
515 * Finishes the preview
516 */
517 private void finish() {
518 getSherlockActivity().onBackPressed();
519 }
520 }