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
.util
.Log
;
15 import android
.view
.LayoutInflater
;
16 import android
.view
.View
;
17 import android
.view
.ViewGroup
;
18 import android
.widget
.BaseAdapter
;
19 import android
.widget
.ListView
;
20 import android
.widget
.TextView
;
22 import com
.actionbarsherlock
.view
.Menu
;
23 import com
.actionbarsherlock
.view
.MenuInflater
;
24 import com
.actionbarsherlock
.view
.MenuItem
;
25 import com
.owncloud
.android
.R
;
26 import com
.owncloud
.android
.datamodel
.OCFile
;
27 import com
.owncloud
.android
.files
.FileMenuFilter
;
28 import com
.owncloud
.android
.lib
.common
.utils
.Log_OC
;
29 import com
.owncloud
.android
.ui
.activity
.FileDisplayActivity
;
30 import com
.owncloud
.android
.ui
.dialog
.ConfirmationDialogFragment
;
31 import com
.owncloud
.android
.ui
.dialog
.LoadingDialog
;
32 import com
.owncloud
.android
.ui
.dialog
.RemoveFileDialogFragment
;
33 import com
.owncloud
.android
.ui
.fragment
.FileFragment
;
35 import java
.io
.BufferedWriter
;
36 import java
.io
.FileInputStream
;
37 import java
.io
.IOException
;
38 import java
.io
.StringWriter
;
39 import java
.util
.ArrayList
;
40 import java
.util
.LinkedList
;
41 import java
.util
.List
;
42 import java
.util
.Queue
;
43 import java
.util
.Scanner
;
45 public class PreviewTextFragment
extends FileFragment
{
46 private static final String EXTRA_FILE
= "FILE";
47 private static final String EXTRA_ACCOUNT
= "ACCOUNT";
48 private static final String TAG
= PreviewTextFragment
.class.getSimpleName();
50 private Account mAccount
;
51 private ListView mTextPreviewList
;
54 * Creates an empty fragment for previews.
56 * MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically
57 * (for instance, when the device is turned a aside).
59 * DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful
62 public PreviewTextFragment() {
71 public View
onCreateView(LayoutInflater inflater
, ViewGroup container
,
72 Bundle savedInstanceState
) {
73 super.onCreateView(inflater
, container
, savedInstanceState
);
74 Log_OC
.e(TAG
, "onCreateView");
77 View ret
= inflater
.inflate(R
.layout
.text_file_preview
, container
, false
);
79 mTextPreviewList
= (ListView
) ret
.findViewById(R
.id
.text_preview_list
);
80 mTextPreviewList
.setAdapter(new TextLineAdapter());
89 public void onCreate(Bundle savedInstanceState
) {
90 super.onCreate(savedInstanceState
);
92 OCFile file
= getFile();
94 Bundle args
= getArguments();
97 file
= args
.getParcelable(FileDisplayActivity
.EXTRA_FILE
);
100 mAccount
= args
.getParcelable(FileDisplayActivity
.EXTRA_ACCOUNT
);
103 if (savedInstanceState
== null
) {
105 throw new IllegalStateException("Instanced with a NULL OCFile");
107 if (mAccount
== null
) {
108 throw new IllegalStateException("Instanced with a NULL ownCloud Account");
111 file
= savedInstanceState
.getParcelable(EXTRA_FILE
);
112 mAccount
= savedInstanceState
.getParcelable(EXTRA_ACCOUNT
);
115 setHasOptionsMenu(true
);
122 public void onSaveInstanceState(Bundle outState
) {
123 super.onSaveInstanceState(outState
);
124 outState
.putParcelable(PreviewImageFragment
.EXTRA_FILE
, getFile());
125 outState
.putParcelable(PreviewImageFragment
.EXTRA_ACCOUNT
, mAccount
);
129 public void onStart() {
131 Log_OC
.e(TAG
, "onStart");
134 private void loadAndShowTextPreview() {
135 new TextLoadAsyncTask().execute(getFile().getStoragePath());
139 * Reads the file to preview and shows its contents. Too critical to be anonymous.
141 private class TextLoadAsyncTask
extends AsyncTask
<Object
, StringWriter
, Void
> {
142 private int TEXTVIEW_WIDTH
;
143 private float TEXTVIEW_SIZE
;
144 private final Queue
<Character
> accumulatedText
= new LinkedList
<Character
>();
145 private final String DIALOG_WAIT_TAG
= "DIALOG_WAIT";
146 private final Rect bounds
= new Rect();
147 private final Paint paint
= new Paint();
149 @SuppressLint("InflateParams")
151 protected void onPreExecute() {
152 ((TextLineAdapter
) mTextPreviewList
.getAdapter()).clear();
153 DisplayMetrics displaymetrics
= new DisplayMetrics();
154 getActivity().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics
);
155 TEXTVIEW_WIDTH
= displaymetrics
.widthPixels
;
156 TEXTVIEW_SIZE
= ((TextView
) ((LayoutInflater
) getActivity().getApplicationContext()
157 .getSystemService(Context
.LAYOUT_INFLATER_SERVICE
))
159 R
.layout
.text_file_preview_list_item
, null
)).getTextSize();
161 paint
.setTextSize(TEXTVIEW_SIZE
);
165 protected Void
doInBackground(java
.lang
.Object
... params
) {
166 if (params
.length
!= 1)
167 throw new IllegalArgumentException("The parameter to " + TextLoadAsyncTask
.class.getName() + " must be the file location only");
168 final String location
= (String
) params
[0];
170 FileInputStream inputStream
= null
;
173 inputStream
= new FileInputStream(location
);
174 sc
= new Scanner(inputStream
);
175 while (sc
.hasNextLine()) {
176 StringWriter target
= new StringWriter();
177 BufferedWriter bufferedWriter
= new BufferedWriter(target
);
178 if (sc
.hasNextLine())
179 bufferedWriter
.write(sc
.nextLine());
180 bufferedWriter
.close();
181 publishProgress(target
);
183 IOException exc
= sc
.ioException();
184 if (exc
!= null
) throw exc
;
185 } catch (IOException e
) {
188 if (inputStream
!= null
) {
191 } catch (IOException e
) {
199 //Add the remaining text, if any
200 while (!accumulatedText
.isEmpty()) {
207 protected void onProgressUpdate(StringWriter
... values
) {
208 super.onProgressUpdate(values
);
209 final char[] newTextAsCharArray
= values
[0].toString().toCharArray();
210 for (char c
: newTextAsCharArray
) {
211 accumulatedText
.add(c
);
216 private synchronized void addLine() {
217 StringBuilder textForThisLine
= new StringBuilder();
219 Character polled
= accumulatedText
.poll();
220 textForThisLine
.append(polled
);
222 while (!isTooLarge(textForThisLine
.toString()) && !accumulatedText
.isEmpty());
223 String line
= textForThisLine
.toString();
224 ((TextLineAdapter
) mTextPreviewList
.getAdapter()).add(line
.contentEquals("null") ?
"" : line
);
227 private boolean isTooLarge(String text
) {
228 paint
.getTextBounds(text
, 0, text
.length(), bounds
);
229 int lineWidth
= (int) Math
.ceil(bounds
.width());
230 return lineWidth
/ TEXTVIEW_WIDTH
> 1;
234 protected void onPostExecute(Void aVoid
) {
235 super.onPostExecute(aVoid
);
236 mTextPreviewList
.setVisibility(View
.VISIBLE
);
237 dismissLoadingDialog();
241 * Show loading dialog
243 public void showLoadingDialog() {
245 LoadingDialog loading
= new LoadingDialog(getResources().getString(R
.string
.wait_a_moment
));
246 FragmentManager fm
= getActivity().getSupportFragmentManager();
247 FragmentTransaction ft
= fm
.beginTransaction();
248 loading
.show(ft
, DIALOG_WAIT_TAG
);
252 * Dismiss loading dialog
254 public void dismissLoadingDialog() {
255 Fragment frag
= getActivity().getSupportFragmentManager().findFragmentByTag(DIALOG_WAIT_TAG
);
257 LoadingDialog loading
= (LoadingDialog
) frag
;
263 private class TextLineAdapter
extends BaseAdapter
{
264 private static final int LIST_ITEM_LAYOUT
= R
.layout
.text_file_preview_list_item
;
265 private final List
<String
> items
= new ArrayList
<String
>();
267 private void add(String line
) {
269 getActivity().runOnUiThread(new Runnable() {
272 notifyDataSetChanged();
277 private void clear() {
279 getActivity().runOnUiThread(new Runnable() {
282 notifyDataSetChanged();
288 public int getCount() {
293 public String
getItem(int position
) {
294 if (position
>= items
.size())
295 throw new IllegalArgumentException();
296 return items
.get(position
);
300 public long getItemId(int position
) {
305 public View
getView(int position
, View convertView
, ViewGroup parent
) {
306 ViewHolder viewHolder
;
307 if (convertView
== null
) {
309 ((LayoutInflater
) getActivity().getApplicationContext()
310 .getSystemService(Context
.LAYOUT_INFLATER_SERVICE
))
312 LIST_ITEM_LAYOUT
, null
);
313 viewHolder
= new ViewHolder();
314 viewHolder
.setLineView((TextView
) convertView
.findViewById(R
.id
.text_preview
));
315 convertView
.setTag(viewHolder
);
317 viewHolder
= (ViewHolder
) convertView
.getTag();
320 viewHolder
.getLineView().setText(items
.get(position
));
326 private static class ViewHolder
{
327 private TextView lineView
;
329 private ViewHolder() {
332 public TextView
getLineView() {
336 public void setLineView(TextView lineView
) {
337 this.lineView
= lineView
;
345 public void onCreateOptionsMenu(Menu menu
, MenuInflater inflater
) {
346 super.onCreateOptionsMenu(menu
, inflater
);
347 inflater
.inflate(R
.menu
.file_actions_menu
, menu
);
354 public void onPrepareOptionsMenu(Menu menu
) {
355 super.onPrepareOptionsMenu(menu
);
357 if (mContainerActivity
.getStorageManager() != null
) {
358 FileMenuFilter mf
= new FileMenuFilter(
360 mContainerActivity
.getStorageManager().getAccount(),
362 getSherlockActivity()
367 // additional restriction for this fragment
368 MenuItem item
= menu
.findItem(R
.id
.action_rename_file
);
370 item
.setVisible(false
);
371 item
.setEnabled(false
);
374 // additional restriction for this fragment
375 item
= menu
.findItem(R
.id
.action_move
);
377 item
.setVisible(false
);
378 item
.setEnabled(false
);
381 // this one doesn't make sense since the file has to be down in order to be previewed
382 item
= menu
.findItem(R
.id
.action_download_file
);
384 item
.setVisible(false
);
385 item
.setEnabled(false
);
393 public boolean onOptionsItemSelected(MenuItem item
) {
394 switch (item
.getItemId()) {
395 case R
.id
.action_share_file
: {
396 mContainerActivity
.getFileOperationsHelper().shareFileWithLink(getFile());
399 case R
.id
.action_unshare_file
: {
400 mContainerActivity
.getFileOperationsHelper().unshareFileWithLink(getFile());
403 case R
.id
.action_open_file_with
: {
407 case R
.id
.action_remove_file
: {
408 RemoveFileDialogFragment dialog
= RemoveFileDialogFragment
.newInstance(getFile());
409 dialog
.show(getFragmentManager(), ConfirmationDialogFragment
.FTAG_CONFIRMATION
);
412 case R
.id
.action_see_details
: {
416 case R
.id
.action_send_file
: {
420 case R
.id
.action_sync_file
: {
421 mContainerActivity
.getFileOperationsHelper().syncFile(getFile());
431 * Update the file of the fragment with file value
433 * @param file The new file to set
435 public void updateFile(OCFile file
) {
439 private void sendFile() {
440 mContainerActivity
.getFileOperationsHelper().sendDownloadedFile(getFile());
443 private void seeDetails() {
444 mContainerActivity
.showDetails(getFile());
448 public void onPause() {
449 Log_OC
.e(TAG
, "onPause");
454 public void onResume() {
456 Log_OC
.e(TAG
, "onResume");
458 loadAndShowTextPreview();
462 public void onDestroy() {
463 Log_OC
.e(TAG
, "onDestroy");
468 public void onStop() {
470 Log_OC
.e(TAG
, "onStop");
474 * Opens the previewed file with an external application.
476 private void openFile() {
477 mContainerActivity
.getFileOperationsHelper().openFile(getFile());
482 * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewTextFragment} to be previewed.
484 * @param file File to test if can be previewed.
485 * @return 'True' if the file can be handled by the fragment.
487 public static boolean canBePreviewed(OCFile file
) {
488 return (file
!= null
&& file
.isDown() && file
.isText());
492 * Finishes the preview
494 private void finish() {
495 getSherlockActivity().onBackPressed();