wip
[pub/Android/ownCloud.git] / src / com / owncloud / android / datamodel / OCFile.java
1 /**
2 * ownCloud Android client application
3 *
4 * Copyright (C) 2012 Bartek Przybylski
5 * Copyright (C) 2015 ownCloud Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2,
9 * as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 package com.owncloud.android.datamodel;
22
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.webkit.MimeTypeMap;
26
27 import com.owncloud.android.lib.common.utils.Log_OC;
28
29 import java.io.File;
30 import java.io.Serializable;
31
32 import third_parties.daveKoeller.AlphanumComparator;
33 public class OCFile implements Parcelable, Comparable<OCFile> {
34
35 public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
36 public OCFile createFromParcel(Parcel source) {
37 return new OCFile(source);
38 }
39
40 public OCFile[] newArray(int size) {
41 return new OCFile[size];
42 }
43 };
44
45 public static final String PATH_SEPARATOR = "/";
46 public static final String ROOT_PATH = PATH_SEPARATOR;
47
48 private static final String TAG = OCFile.class.getSimpleName();
49
50 private long mId;
51 private long mParentId;
52 private long mLength;
53 private long mCreationTimestamp;
54 private long mModifiedTimestamp;
55 private long mModifiedTimestampAtLastSyncForData;
56 private String mRemotePath;
57 private String mLocalPath;
58 private String mMimeType;
59 private boolean mNeedsUpdating;
60 private long mLastSyncDateForProperties;
61 private long mLastSyncDateForData;
62 private boolean mFavorite;
63
64 private String mEtag;
65
66 private boolean mShareByLink;
67 private String mPublicLink;
68
69 private String mPermissions;
70 private String mRemoteId;
71
72 private boolean mNeedsUpdateThumbnail;
73
74 private boolean mIsDownloading;
75
76
77 /**
78 * Create new {@link OCFile} with given path.
79 * <p/>
80 * The path received must be URL-decoded. Path separator must be OCFile.PATH_SEPARATOR, and it must be the first character in 'path'.
81 *
82 * @param path The remote path of the file.
83 */
84 public OCFile(String path) {
85 resetData();
86 mNeedsUpdating = false;
87 if (path == null || path.length() <= 0 || !path.startsWith(PATH_SEPARATOR)) {
88 throw new IllegalArgumentException("Trying to create a OCFile with a non valid remote path: " + path);
89 }
90 mRemotePath = path;
91 }
92
93 /**
94 * Reconstruct from parcel
95 *
96 * @param source The source parcel
97 */
98 private OCFile(Parcel source) {
99 mId = source.readLong();
100 mParentId = source.readLong();
101 mLength = source.readLong();
102 mCreationTimestamp = source.readLong();
103 mModifiedTimestamp = source.readLong();
104 mModifiedTimestampAtLastSyncForData = source.readLong();
105 mRemotePath = source.readString();
106 mLocalPath = source.readString();
107 mMimeType = source.readString();
108 mNeedsUpdating = source.readInt() == 0;
109 mFavorite = source.readInt() == 1;
110 mLastSyncDateForProperties = source.readLong();
111 mLastSyncDateForData = source.readLong();
112 mEtag = source.readString();
113 mShareByLink = source.readInt() == 1;
114 mPublicLink = source.readString();
115 mPermissions = source.readString();
116 mRemoteId = source.readString();
117 mNeedsUpdateThumbnail = source.readInt() == 0;
118 mIsDownloading = source.readInt() == 0;
119
120 }
121
122 @Override
123 public void writeToParcel(Parcel dest, int flags) {
124 dest.writeLong(mId);
125 dest.writeLong(mParentId);
126 dest.writeLong(mLength);
127 dest.writeLong(mCreationTimestamp);
128 dest.writeLong(mModifiedTimestamp);
129 dest.writeLong(mModifiedTimestampAtLastSyncForData);
130 dest.writeString(mRemotePath);
131 dest.writeString(mLocalPath);
132 dest.writeString(mMimeType);
133 dest.writeInt(mNeedsUpdating ? 1 : 0);
134 dest.writeInt(mFavorite ? 1 : 0);
135 dest.writeLong(mLastSyncDateForProperties);
136 dest.writeLong(mLastSyncDateForData);
137 dest.writeString(mEtag);
138 dest.writeInt(mShareByLink ? 1 : 0);
139 dest.writeString(mPublicLink);
140 dest.writeString(mPermissions);
141 dest.writeString(mRemoteId);
142 dest.writeInt(mNeedsUpdateThumbnail ? 1 : 0);
143 dest.writeInt(mIsDownloading ? 1 : 0);
144 }
145
146 /**
147 * Gets the ID of the file
148 *
149 * @return the file ID
150 */
151 public long getFileId() {
152 return mId;
153 }
154
155 /**
156 * Returns the remote path of the file on ownCloud
157 *
158 * @return The remote path to the file
159 */
160 public String getRemotePath() {
161 return mRemotePath;
162 }
163
164 /**
165 * Can be used to check, whether or not this file exists in the database
166 * already
167 *
168 * @return true, if the file exists in the database
169 */
170 public boolean fileExists() {
171 return mId != -1;
172 }
173
174 /**
175 * Use this to find out if this file is a folder.
176 *
177 * @return true if it is a folder
178 */
179 public boolean isFolder() {
180 return mMimeType != null && mMimeType.equals("DIR");
181 }
182
183 /**
184 * Use this to check if this file is available locally
185 *
186 * @return true if it is
187 */
188 public boolean isDown() {
189 if (mLocalPath != null && mLocalPath.length() > 0) {
190 File file = new File(mLocalPath);
191 return (file.exists());
192 }
193 return false;
194 }
195
196 /**
197 * The path, where the file is stored locally
198 *
199 * @return The local path to the file
200 */
201 public String getStoragePath() {
202 return mLocalPath;
203 }
204
205 /**
206 * Can be used to set the path where the file is stored
207 *
208 * @param storage_path to set
209 */
210 public void setStoragePath(String storage_path) {
211 mLocalPath = storage_path;
212 }
213
214 /**
215 * Get a UNIX timestamp of the file creation time
216 *
217 * @return A UNIX timestamp of the time that file was created
218 */
219 public long getCreationTimestamp() {
220 return mCreationTimestamp;
221 }
222
223 /**
224 * Set a UNIX timestamp of the time the file was created
225 *
226 * @param creation_timestamp to set
227 */
228 public void setCreationTimestamp(long creation_timestamp) {
229 mCreationTimestamp = creation_timestamp;
230 }
231
232 /**
233 * Get a UNIX timestamp of the file modification time.
234 *
235 * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server
236 * in the last synchronization of the properties of this file.
237 */
238 public long getModificationTimestamp() {
239 return mModifiedTimestamp;
240 }
241
242 /**
243 * Set a UNIX timestamp of the time the time the file was modified.
244 * <p/>
245 * To update with the value returned by the server in every synchronization of the properties
246 * of this file.
247 *
248 * @param modification_timestamp to set
249 */
250 public void setModificationTimestamp(long modification_timestamp) {
251 mModifiedTimestamp = modification_timestamp;
252 }
253
254
255 /**
256 * Get a UNIX timestamp of the file modification time.
257 *
258 * @return A UNIX timestamp of the modification time, corresponding to the value returned by the server
259 * in the last synchronization of THE CONTENTS of this file.
260 */
261 public long getModificationTimestampAtLastSyncForData() {
262 return mModifiedTimestampAtLastSyncForData;
263 }
264
265 /**
266 * Set a UNIX timestamp of the time the time the file was modified.
267 * <p/>
268 * To update with the value returned by the server in every synchronization of THE CONTENTS
269 * of this file.
270 *
271 * @param modificationTimestamp to set
272 */
273 public void setModificationTimestampAtLastSyncForData(long modificationTimestamp) {
274 mModifiedTimestampAtLastSyncForData = modificationTimestamp;
275 }
276
277
278 /**
279 * Returns the filename and "/" for the root directory
280 *
281 * @return The name of the file
282 */
283 public String getFileName() {
284 File f = new File(getRemotePath());
285 return f.getName().length() == 0 ? ROOT_PATH : f.getName();
286 }
287
288 /**
289 * Sets the name of the file
290 * <p/>
291 * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root
292 * directory
293 */
294 public void setFileName(String name) {
295 Log_OC.d(TAG, "OCFile name changin from " + mRemotePath);
296 if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) &&
297 !mRemotePath.equals(ROOT_PATH)) {
298 String parent = (new File(getRemotePath())).getParent();
299 parent = (parent.endsWith(PATH_SEPARATOR)) ? parent : parent + PATH_SEPARATOR;
300 mRemotePath = parent + name;
301 if (isFolder()) {
302 mRemotePath += PATH_SEPARATOR;
303 }
304 Log_OC.d(TAG, "OCFile name changed to " + mRemotePath);
305 }
306 }
307
308 /**
309 * Can be used to get the Mimetype
310 *
311 * @return the Mimetype as a String
312 */
313 public String getMimetype() {
314 return mMimeType;
315 }
316
317 /**
318 * Adds a file to this directory. If this file is not a directory, an
319 * exception gets thrown.
320 *
321 * @param file to add
322 * @throws IllegalStateException if you try to add a something and this is
323 * not a directory
324 */
325 public void addFile(OCFile file) throws IllegalStateException {
326 if (isFolder()) {
327 file.mParentId = mId;
328 mNeedsUpdating = true;
329 return;
330 }
331 throw new IllegalStateException(
332 "This is not a directory where you can add stuff to!");
333 }
334
335 /**
336 * Used internally. Reset all file properties
337 */
338 private void resetData() {
339 mId = -1;
340 mRemotePath = null;
341 mParentId = 0;
342 mLocalPath = null;
343 mMimeType = null;
344 mLength = 0;
345 mCreationTimestamp = 0;
346 mModifiedTimestamp = 0;
347 mModifiedTimestampAtLastSyncForData = 0;
348 mLastSyncDateForProperties = 0;
349 mLastSyncDateForData = 0;
350 mFavorite = false;
351 mNeedsUpdating = false;
352 mEtag = null;
353 mShareByLink = false;
354 mPublicLink = null;
355 mPermissions = null;
356 mRemoteId = null;
357 mNeedsUpdateThumbnail = false;
358 mIsDownloading = false;
359 }
360
361 /**
362 * Sets the ID of the file
363 *
364 * @param file_id to set
365 */
366 public void setFileId(long file_id) {
367 mId = file_id;
368 }
369
370 /**
371 * Sets the Mime-Type of the
372 *
373 * @param mimetype to set
374 */
375 public void setMimetype(String mimetype) {
376 mMimeType = mimetype;
377 }
378
379 /**
380 * Sets the ID of the parent folder
381 *
382 * @param parent_id to set
383 */
384 public void setParentId(long parent_id) {
385 mParentId = parent_id;
386 }
387
388 /**
389 * Sets the file size in bytes
390 *
391 * @param file_len to set
392 */
393 public void setFileLength(long file_len) {
394 mLength = file_len;
395 }
396
397 /**
398 * Returns the size of the file in bytes
399 *
400 * @return The filesize in bytes
401 */
402 public long getFileLength() {
403 return mLength;
404 }
405
406 /**
407 * Returns the ID of the parent Folder
408 *
409 * @return The ID
410 */
411 public long getParentId() {
412 return mParentId;
413 }
414
415 /**
416 * Check, if this file needs updating
417 *
418 * @return
419 */
420 public boolean needsUpdatingWhileSaving() {
421 return mNeedsUpdating;
422 }
423
424 public boolean needsUpdateThumbnail() {
425 return mNeedsUpdateThumbnail;
426 }
427
428 public void setNeedsUpdateThumbnail(boolean needsUpdateThumbnail) {
429 this.mNeedsUpdateThumbnail = needsUpdateThumbnail;
430 }
431
432 public long getLastSyncDateForProperties() {
433 return mLastSyncDateForProperties;
434 }
435
436 public void setLastSyncDateForProperties(long lastSyncDate) {
437 mLastSyncDateForProperties = lastSyncDate;
438 }
439
440 public long getLastSyncDateForData() {
441 return mLastSyncDateForData;
442 }
443
444 public void setLastSyncDateForData(long lastSyncDate) {
445 mLastSyncDateForData = lastSyncDate;
446 }
447
448 public void setFavorite(boolean favorite) {
449 mFavorite = favorite;
450 }
451
452 public boolean isFavorite() {
453 return mFavorite;
454 }
455
456 @Override
457 public int describeContents() {
458 return super.hashCode();
459 }
460
461 @Override
462 public int compareTo(OCFile another) {
463 if (isFolder() && another.isFolder()) {
464 return getRemotePath().toLowerCase().compareTo(another.getRemotePath().toLowerCase());
465 } else if (isFolder()) {
466 return -1;
467 } else if (another.isFolder()) {
468 return 1;
469 }
470 return new AlphanumComparator().compare(this, another);
471 }
472
473 @Override
474 public boolean equals(Object o) {
475 if (o instanceof OCFile) {
476 OCFile that = (OCFile) o;
477 if (that != null) {
478 return this.mId == that.mId;
479 }
480 }
481
482 return false;
483 }
484
485 @Override
486 public String toString() {
487 String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, " +
488 "parentId=%s, favorite=%s etag=%s]";
489 asString = String.format(asString, Long.valueOf(mId), getFileName(), mMimeType, isDown(),
490 mLocalPath, mRemotePath, Long.valueOf(mParentId), Boolean.valueOf(mFavorite),
491 mEtag);
492 return asString;
493 }
494
495 public String getEtag() {
496 return mEtag;
497 }
498
499 public void setEtag(String etag) {
500 this.mEtag = etag;
501 }
502
503
504 public boolean isShareByLink() {
505 return mShareByLink;
506 }
507
508 public void setShareByLink(boolean shareByLink) {
509 this.mShareByLink = shareByLink;
510 }
511
512 public String getPublicLink() {
513 return mPublicLink;
514 }
515
516 public void setPublicLink(String publicLink) {
517 this.mPublicLink = publicLink;
518 }
519
520 public long getLocalModificationTimestamp() {
521 if (mLocalPath != null && mLocalPath.length() > 0) {
522 File f = new File(mLocalPath);
523 return f.lastModified();
524 }
525 return 0;
526 }
527
528 /**
529 * @return 'True' if the file contains audio
530 */
531 public boolean isAudio() {
532 return (mMimeType != null && mMimeType.startsWith("audio/"));
533 }
534
535 /**
536 * @return 'True' if the file contains video
537 */
538 public boolean isVideo() {
539 return (mMimeType != null && mMimeType.startsWith("video/"));
540 }
541
542 /**
543 * @return 'True' if the file contains an image
544 */
545 public boolean isImage() {
546 return ((mMimeType != null && mMimeType.startsWith("image/")) ||
547 getMimeTypeFromName().startsWith("image/"));
548 }
549
550 /**
551 * @return 'True' if the file is simple text (e.g. not application-dependent, like .doc or .docx)
552 */
553 public boolean isText() {
554 return ((mMimeType != null && mMimeType.startsWith("text/")) ||
555 getMimeTypeFromName().startsWith("text/"));
556 }
557
558 public String getMimeTypeFromName() {
559 String extension = "";
560 int pos = mRemotePath.lastIndexOf('.');
561 if (pos >= 0) {
562 extension = mRemotePath.substring(pos + 1);
563 }
564 String result = MimeTypeMap.getSingleton().
565 getMimeTypeFromExtension(extension.toLowerCase());
566 return (result != null) ? result : "";
567 }
568
569 /**
570 * @return 'True' if the file is hidden
571 */
572 public boolean isHidden() {
573 return getFileName().startsWith(".");
574 }
575
576 public String getPermissions() {
577 return mPermissions;
578 }
579
580 public void setPermissions(String permissions) {
581 this.mPermissions = permissions;
582 }
583
584 public String getRemoteId() {
585 return mRemoteId;
586 }
587
588 public void setRemoteId(String remoteId) {
589 this.mRemoteId = remoteId;
590 }
591
592 public boolean isDownloading() {
593 return mIsDownloading;
594 }
595
596 public void setDownloading(boolean isDownloading) {
597 this.mIsDownloading = isDownloading;
598 }
599
600 public boolean isSynchronizing() {
601 // TODO real implementation
602 return false;
603 }
604 }