1 package com
.owncloud
.android
.ui
.preview
;
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
;
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
;
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
;
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();
49 private Account mAccount
;
50 private ListView mTextPreviewList
;
53 * Creates an empty fragment for previews.
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).
58 * DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful
61 public PreviewTextFragment() {
70 public View
onCreateView(LayoutInflater inflater
, ViewGroup container
,
71 Bundle savedInstanceState
) {
72 super.onCreateView(inflater
, container
, savedInstanceState
);
73 Log_OC
.e(TAG
, "onCreateView");
76 View ret
= inflater
.inflate(R
.layout
.text_file_preview
, container
, false
);
78 mTextPreviewList
= (ListView
) ret
.findViewById(R
.id
.text_preview_list
);
79 mTextPreviewList
.setAdapter(new TextLineAdapter());
88 public void onCreate(Bundle savedInstanceState
) {
89 super.onCreate(savedInstanceState
);
91 OCFile file
= getFile();
93 Bundle args
= getArguments();
96 file
= args
.getParcelable(FileDisplayActivity
.EXTRA_FILE
);
99 mAccount
= args
.getParcelable(FileDisplayActivity
.EXTRA_ACCOUNT
);
102 if (savedInstanceState
== null
) {
104 throw new IllegalStateException("Instanced with a NULL OCFile");
106 if (mAccount
== null
) {
107 throw new IllegalStateException("Instanced with a NULL ownCloud Account");
110 file
= savedInstanceState
.getParcelable(EXTRA_FILE
);
111 mAccount
= savedInstanceState
.getParcelable(EXTRA_ACCOUNT
);
114 setHasOptionsMenu(true
);
121 public void onSaveInstanceState(Bundle outState
) {
122 super.onSaveInstanceState(outState
);
123 outState
.putParcelable(PreviewImageFragment
.EXTRA_FILE
, getFile());
124 outState
.putParcelable(PreviewImageFragment
.EXTRA_ACCOUNT
, mAccount
);
128 public void onStart() {
130 Log_OC
.e(TAG
, "onStart");
133 private void loadAndShowTextPreview() {
134 new TextLoadAsyncTask().execute(getFile().getStoragePath());
138 * Reads the file to preview and shows its contents. Too critical to be anonymous.
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();
148 @SuppressLint("InflateParams")
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
))
158 R
.layout
.text_file_preview_list_item
, null
)).getTextSize();
160 paint
.setTextSize(TEXTVIEW_SIZE
);
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];
169 FileInputStream inputStream
= null
;
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
);
182 IOException exc
= sc
.ioException();
183 if (exc
!= null
) throw exc
;
184 } catch (IOException e
) {
187 if (inputStream
!= null
) {
190 } catch (IOException e
) {
198 //Add the remaining text, if any
199 while (!accumulatedText
.isEmpty()) {
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
);
215 private synchronized void addLine() {
216 StringBuilder textForThisLine
= new StringBuilder();
218 Character polled
= accumulatedText
.poll();
219 textForThisLine
.append(polled
);
221 while (!isTooLarge(textForThisLine
.toString()) && !accumulatedText
.isEmpty());
222 String line
= textForThisLine
.toString();
223 ((TextLineAdapter
) mTextPreviewList
.getAdapter()).add(line
.contentEquals("null") ?
"" : line
);
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;
233 protected void onPostExecute(Void aVoid
) {
234 super.onPostExecute(aVoid
);
235 mTextPreviewList
.setVisibility(View
.VISIBLE
);
236 dismissLoadingDialog();
240 * Show loading dialog
242 public void showLoadingDialog() {
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
);
251 * Dismiss loading dialog
253 public void dismissLoadingDialog() {
254 Fragment frag
= getActivity().getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG
);
256 LoadingDialog loading
= (LoadingDialog
) frag
;
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
>();
266 private void add(String line
) {
268 getActivity().runOnUiThread(new Runnable() {
271 notifyDataSetChanged();
276 private void clear() {
278 getActivity().runOnUiThread(new Runnable() {
281 notifyDataSetChanged();
287 public int getCount() {
292 public String
getItem(int position
) {
293 if (position
>= items
.size())
294 throw new IllegalArgumentException();
295 return items
.get(position
);
299 public long getItemId(int position
) {
304 public View
getView(int position
, View convertView
, ViewGroup parent
) {
305 ViewHolder viewHolder
;
306 if (convertView
== null
) {
308 ((LayoutInflater
) getActivity().getApplicationContext()
309 .getSystemService(Context
.LAYOUT_INFLATER_SERVICE
))
311 LIST_ITEM_LAYOUT
, null
);
312 viewHolder
= new ViewHolder();
313 viewHolder
.setLineView((TextView
) convertView
.findViewById(R
.id
.text_preview
));
314 convertView
.setTag(viewHolder
);
316 viewHolder
= (ViewHolder
) convertView
.getTag();
319 viewHolder
.getLineView().setText(items
.get(position
));
325 private static class ViewHolder
{
326 private TextView lineView
;
328 private ViewHolder() {
331 public TextView
getLineView() {
335 public void setLineView(TextView lineView
) {
336 this.lineView
= lineView
;
344 public void onCreateOptionsMenu(Menu menu
, MenuInflater inflater
) {
345 super.onCreateOptionsMenu(menu
, inflater
);
346 inflater
.inflate(R
.menu
.file_actions_menu
, menu
);
353 public void onPrepareOptionsMenu(Menu menu
) {
354 super.onPrepareOptionsMenu(menu
);
356 if (mContainerActivity
.getStorageManager() != null
) {
357 FileMenuFilter mf
= new FileMenuFilter(
359 mContainerActivity
.getStorageManager().getAccount(),
361 getSherlockActivity()
366 // additional restriction for this fragment
367 MenuItem item
= menu
.findItem(R
.id
.action_rename_file
);
369 item
.setVisible(false
);
370 item
.setEnabled(false
);
373 // additional restriction for this fragment
374 item
= menu
.findItem(R
.id
.action_move
);
376 item
.setVisible(false
);
377 item
.setEnabled(false
);
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
);
383 item
.setVisible(false
);
384 item
.setEnabled(false
);
387 item
= menu
.findItem(R
.id
.action_settings
);
389 item
.setVisible(false
);
390 item
.setEnabled(false
);
393 item
= menu
.findItem(R
.id
.action_logger
);
395 item
.setVisible(false
);
396 item
.setEnabled(false
);
399 item
= menu
.findItem(R
.id
.action_sync_file
);
401 item
.setVisible(false
);
402 item
.setEnabled(false
);
405 item
= menu
.findItem(R
.id
.action_sync_account
);
407 item
.setVisible(false
);
408 item
.setEnabled(false
);
416 public boolean onOptionsItemSelected(MenuItem item
) {
417 switch (item
.getItemId()) {
418 case R
.id
.action_share_file
: {
419 mContainerActivity
.getFileOperationsHelper().shareFileWithLink(getFile());
422 case R
.id
.action_unshare_file
: {
423 mContainerActivity
.getFileOperationsHelper().unshareFileWithLink(getFile());
426 case R
.id
.action_open_file_with
: {
430 case R
.id
.action_remove_file
: {
431 RemoveFileDialogFragment dialog
= RemoveFileDialogFragment
.newInstance(getFile());
432 dialog
.show(getFragmentManager(), ConfirmationDialogFragment
.FTAG_CONFIRMATION
);
435 case R
.id
.action_see_details
: {
439 case R
.id
.action_send_file
: {
443 case R
.id
.action_sync_file
: {
444 mContainerActivity
.getFileOperationsHelper().syncFile(getFile());
454 * Update the file of the fragment with file value
456 * @param file The new file to set
458 public void updateFile(OCFile file
) {
462 private void sendFile() {
463 mContainerActivity
.getFileOperationsHelper().sendDownloadedFile(getFile());
466 private void seeDetails() {
467 mContainerActivity
.showDetails(getFile());
471 public void onPause() {
472 Log_OC
.e(TAG
, "onPause");
477 public void onResume() {
479 Log_OC
.e(TAG
, "onResume");
481 loadAndShowTextPreview();
485 public void onDestroy() {
486 Log_OC
.e(TAG
, "onDestroy");
491 public void onStop() {
493 Log_OC
.e(TAG
, "onStop");
497 * Opens the previewed file with an external application.
499 private void openFile() {
500 mContainerActivity
.getFileOperationsHelper().openFile(getFile());
505 * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewTextFragment} to be previewed.
507 * @param file File to test if can be previewed.
508 * @return 'True' if the file can be handled by the fragment.
510 public static boolean canBePreviewed(OCFile file
) {
511 return (file
!= null
&& file
.isDown() && file
.isText());
515 * Finishes the preview
517 private void finish() {
518 getSherlockActivity().onBackPressed();