From af352377ab929ce8571e5060ddca0414d41d6d45 Mon Sep 17 00:00:00 2001 From: k3b <1374583+k3b@users.noreply.github.com> Date: Sat, 25 Apr 2020 11:14:35 +0200 Subject: [PATCH] #169: lib-test --- .../backup/Backup2ZipService.java | 14 +- .../ImageDetailActivityViewPager.java | 41 +-- .../androFotoFinder/tagDB/TagWorflow.java | 7 +- .../de/k3b/android/io/AndroidFileFacade.java | 11 +- .../widget/FilePermissionActivity.java | 12 +- fastlane/fd2fastlane.py | 22 +- .../src/main/java/de/k3b/io/FileCommands.java | 280 ++++++++++-------- .../src/main/java/de/k3b/io/FileFacade.java | 47 ++- .../main/java/de/k3b/io/FileProcessor.java | 138 ++++++--- .../src/main/java/de/k3b/io/FileUtils.java | 72 +++-- .../src/main/java/de/k3b/io/FileWrapper.java | 150 ++++++++++ fotolib2/src/main/java/de/k3b/io/IFile.java | 4 + .../de/k3b/io/collections/SelectedFiles.java | 8 + .../main/java/de/k3b/media/ExifInterface.java | 13 +- .../java/de/k3b/media/ExifInterfaceEx.java | 7 +- .../PhotoProperties2ExistingFileSaver.java | 13 +- .../PhotoPropertiesBulkUpdateService.java | 49 ++- .../media/PhotoPropertiesUpdateHandler.java | 10 +- .../k3b/media/PhotoPropertiesXmpSegment.java | 11 +- .../main/java/de/k3b/media/XmpSegment.java | 31 +- fotolib2/src/test/java/de/k3b/TestUtil.java | 8 +- .../io/FileCommandAutoIntegrationTests.java | 45 +-- .../de/k3b/io/FileNameProcessorTests.java | 2 + 23 files changed, 688 insertions(+), 307 deletions(-) create mode 100644 fotolib2/src/main/java/de/k3b/io/FileWrapper.java diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/backup/Backup2ZipService.java b/app/src/main/java/de/k3b/android/androFotoFinder/backup/Backup2ZipService.java index 8ca9daad..8cd22169 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/backup/Backup2ZipService.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/backup/Backup2ZipService.java @@ -34,6 +34,8 @@ import de.k3b.android.androFotoFinder.queries.FotoSql; import de.k3b.android.androFotoFinder.tagDB.TagSql; import de.k3b.database.QueryParameter; +import de.k3b.io.FileFacade; +import de.k3b.io.IFile; import de.k3b.io.IItemSaver; import de.k3b.io.IProgessListener; import de.k3b.io.StringUtils; @@ -126,10 +128,10 @@ public IZipConfig execute() { boolean addPhotos = BackupOptions.allOf(jobOptions, BackupOptions.PHOTOS_WITH_EXISTING_XMP); if (addPhotos) { // pipline for (IPhotoProperties item: query(filter)) : Zip+=File(item) - final IItemSaver file2ZipSaver = new IItemSaver() { + final IItemSaver file2ZipSaver = new IItemSaver() { @Override - public boolean save(File item) { - CompressItem compressItem = job.addToCompressQue("", item); + public boolean save(IFile item) { + CompressItem compressItem = addCompressItem((FileFacade) item); /* if (PhotoPropertiesUtil.isImage(item.getName(), PhotoPropertiesUtil.IMG_TYPE_COMPRESSED)) { // performance improvement: jpg-s should not be compressed @@ -171,6 +173,12 @@ public boolean save(File item) { return null; } + // TODO add IFile to job + @Deprecated + public CompressItem addCompressItem(FileFacade item) { + return job.addToCompressQue("", item.getFile()); + } + /** * @return get query without filte-DateModified-min/max and with added zipConfig.getDateModifiedFrom */ diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailActivityViewPager.java b/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailActivityViewPager.java index f5bcf64c..f415c605 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailActivityViewPager.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/imagedetail/ImageDetailActivityViewPager.java @@ -79,10 +79,12 @@ import de.k3b.database.QueryParameter; import de.k3b.geo.api.GeoPointDto; import de.k3b.geo.io.GeoUri; +import de.k3b.io.FileFacade; import de.k3b.io.FileProcessor; import de.k3b.io.FileUtils; import de.k3b.io.GalleryFilterParameter; import de.k3b.io.IDirectory; +import de.k3b.io.IFile; import de.k3b.io.StringUtils; import de.k3b.io.collections.SelectedFiles; import de.k3b.media.PhotoPropertiesUtil; @@ -121,6 +123,7 @@ public class ImageDetailActivityViewPager extends BaseActivity implements Common /** if smaller that these millisecs then the actionbar autohide is disabled */ private static final int DISABLE_HIDE_ACTIONBAR = 700; private static final int NOMEDIA_GALLERY = 8227; + private static final String MIME = "*/*"; // how many changes have been made. if != 0 parent activity must invalidate cached data private static int mModifyCount = 0; @@ -667,28 +670,28 @@ private boolean checkForIncompleteMediaDatabase(String jpgFullFilePath, String w private void onRenameFileAnswer(final CharSequence title, final SelectedFiles currentFoto, final long fotoId, final String fotoSourcePath, final String newFileName) { - File src = new File(fotoSourcePath); - File dest = new File(src.getParentFile(), newFileName); + IFile src = FileFacade.convert(new File(fotoSourcePath)); + IFile dest = src.getParentFile().create(newFileName, src.getMime()); - File srcXmpShort = FileProcessor.getSidecar(src, false); + IFile srcXmpShort = FileProcessor.getSidecar(src, false); boolean hasSideCarShort = ((srcXmpShort != null) && (mFileCommands.osFileExists(srcXmpShort))); - File srcXmpLong = FileProcessor.getSidecar(src, true); + IFile srcXmpLong = FileProcessor.getSidecar(src, true); boolean hasSideCarLong = ((srcXmpLong != null) && (mFileCommands.osFileExists(srcXmpLong))); - File destXmpShort = FileProcessor.getSidecar(dest, false); - File destXmpLong = FileProcessor.getSidecar(dest, true); + IFile destXmpShort = FileProcessor.getSidecar(dest, false); + IFile destXmpLong = FileProcessor.getSidecar(dest, true); if (src.equals(dest)) return; // new name == old name ==> nothing to do String errorMessage = null; if (hasSideCarShort && mFileCommands.osFileExists(destXmpShort)) { - errorMessage = getString(R.string.image_err_file_exists_format, destXmpShort.getAbsoluteFile()); + errorMessage = getString(R.string.image_err_file_exists_format, destXmpShort.getAbsolutePath()); } if (hasSideCarLong && mFileCommands.osFileExists(destXmpLong)) { - errorMessage = getString(R.string.image_err_file_exists_format, destXmpLong.getAbsoluteFile()); + errorMessage = getString(R.string.image_err_file_exists_format, destXmpLong.getAbsolutePath()); } if (mFileCommands.osFileExists(dest)) { - errorMessage = getString(R.string.image_err_file_exists_format, dest.getAbsoluteFile()); + errorMessage = getString(R.string.image_err_file_exists_format, dest.getAbsolutePath()); } PhotoChangeNotifyer.setPhotoChangedListener(this); @@ -700,16 +703,16 @@ private void onRenameFileAnswer(final CharSequence title, final SelectedFiles cu mModifyCount++; } else { // rename failed - errorMessage = getString(R.string.image_err_file_rename_format, src.getAbsoluteFile()); + errorMessage = getString(R.string.image_err_file_rename_format, src.getAbsolutePath()); Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show(); } } - private boolean osRenameTo(final CharSequence title, final File dest, final SelectedFiles currentFoto) { + private boolean osRenameTo(final CharSequence title, final IFile dest, final SelectedFiles currentFoto) { // close rename dialog to allow messagebox that prepares to ask closeDialogIfNeeded(); - File missingRoot = getMissingRootDirFileOrNull( - "ImageDetailActivityViewPager.osRenameTo", currentFoto.getFiles()); + IFile missingRoot = getMissingRootDirFileOrNull( + "ImageDetailActivityViewPager.osRenameTo", currentFoto.getIFiles()); if (missingRoot != null) { // ask for needed permissions requestRootUriDialog(missingRoot, title, @@ -1090,22 +1093,22 @@ private void onRenameSubDirAnswer(final CharSequence title, SelectedFiles curren File src = new File(fotoSourcePath); File dest = new File(src.getParentFile(), newFileName); - File srcXmpShort = FileProcessor.getSidecar(src, false); + IFile srcXmpShort = FileProcessor.getSidecar(src, false); boolean hasSideCarShort = ((srcXmpShort != null) && (mFileCommands.osFileExists(srcXmpShort))); - File srcXmpLong = FileProcessor.getSidecar(src, true); + IFile srcXmpLong = FileProcessor.getSidecar(src, true); boolean hasSideCarLong = ((srcXmpLong != null) && (mFileCommands.osFileExists(srcXmpLong))); - File destXmpShort = FileProcessor.getSidecar(dest, false); - File destXmpLong = FileProcessor.getSidecar(dest, true); + IFile destXmpShort = FileProcessor.getSidecar(dest, false); + IFile destXmpLong = FileProcessor.getSidecar(dest, true); if (src.equals(dest)) return; // new name == old name ==> nothing to do String errorMessage = null; if (hasSideCarShort && mFileCommands.osFileExists(destXmpShort)) { - errorMessage = getString(R.string.image_err_file_exists_format, destXmpShort.getAbsoluteFile()); + errorMessage = getString(R.string.image_err_file_exists_format, destXmpShort.getAbsolutePath()); } if (hasSideCarLong && mFileCommands.osFileExists(destXmpLong)) { - errorMessage = getString(R.string.image_err_file_exists_format, destXmpLong.getAbsoluteFile()); + errorMessage = getString(R.string.image_err_file_exists_format, destXmpLong.getAbsolutePath()); } if (mFileCommands.osFileExists(dest)) { errorMessage = getString(R.string.image_err_file_exists_format, dest.getAbsoluteFile()); diff --git a/app/src/main/java/de/k3b/android/androFotoFinder/tagDB/TagWorflow.java b/app/src/main/java/de/k3b/android/androFotoFinder/tagDB/TagWorflow.java index 662f8f81..694a18d3 100644 --- a/app/src/main/java/de/k3b/android/androFotoFinder/tagDB/TagWorflow.java +++ b/app/src/main/java/de/k3b/android/androFotoFinder/tagDB/TagWorflow.java @@ -33,6 +33,7 @@ import de.k3b.android.androFotoFinder.queries.IMediaRepositoryApi; import de.k3b.android.io.AndroidFileCommands; import de.k3b.io.FileCommands; +import de.k3b.io.IFile; import de.k3b.io.IProgessListener; import de.k3b.io.collections.SelectedFiles; import de.k3b.media.MediaFormatter; @@ -65,7 +66,7 @@ public TagWorflow init(Activity context, SelectedFiles selectedItems, List this.items = loadTagWorflowItems(context, (selectedItems == null) ? null : selectedItems.toIdString(), anyOfTags); for (TagSql.TagWorflowItem item : items) { List tags = item.tags; - File xmpFile = FileCommands.getExistingSidecarOrNull(item.path); + IFile xmpFile = FileCommands.getExistingSidecarOrNull(item.path); if ((xmpFile != null) && xmpFile.exists() && (item.xmpLastModifiedDate < xmpFile.lastModified())){ // || (tags == null) || (tags.size() == 0)) { // xmp has been updated since last db update. tags = loadTags(xmpFile); @@ -170,13 +171,13 @@ public boolean onProgress(int itemCount, int total, String message) { return true; } - private List loadTags(File xmpFile) { + private List loadTags(IFile xmpFile) { PhotoPropertiesXmpSegment xmp = loadXmp(xmpFile); return (xmp == null) ? null : xmp.getTags(); } @NonNull - private PhotoPropertiesXmpSegment loadXmp(File xmpFile) { + private PhotoPropertiesXmpSegment loadXmp(IFile xmpFile) { if ((xmpFile != null) && (xmpFile.exists())) { try { PhotoPropertiesXmpSegment xmp = new PhotoPropertiesXmpSegment(); diff --git a/app/src/main/java/de/k3b/android/io/AndroidFileFacade.java b/app/src/main/java/de/k3b/android/io/AndroidFileFacade.java index 3314601b..40ccfaa7 100644 --- a/app/src/main/java/de/k3b/android/io/AndroidFileFacade.java +++ b/app/src/main/java/de/k3b/android/io/AndroidFileFacade.java @@ -53,15 +53,6 @@ public static void setContext(DocumentFileTranslator documentFileTranslator) { AndroidFileFacade.documentFileTranslator = documentFileTranslator; } - public static AndroidFileFacade[] get(File[] files) { - AndroidFileFacade f[] = new AndroidFileFacade[files.length]; - for (int i = 0; i < files.length; i++) { - f[i] = new AndroidFileFacade(files[i]); - } - - return f; - } - @Override public boolean renameTo(IFile newName) { if (exists() && !newName.exists()) { @@ -71,7 +62,7 @@ public boolean renameTo(IFile newName) { } if (copyImpl((AndroidFileFacade) newName, true)) { - setFile(((AndroidFileFacade) newName).getFile()); + setFile(newName.getFile()); return true; } } diff --git a/app/src/main/java/de/k3b/android/widget/FilePermissionActivity.java b/app/src/main/java/de/k3b/android/widget/FilePermissionActivity.java index 65ced302..e552d4c3 100644 --- a/app/src/main/java/de/k3b/android/widget/FilePermissionActivity.java +++ b/app/src/main/java/de/k3b/android/widget/FilePermissionActivity.java @@ -38,7 +38,9 @@ import de.k3b.android.androFotoFinder.Global; import de.k3b.android.androFotoFinder.R; import de.k3b.android.io.DocumentFileTranslator; +import de.k3b.io.FileFacade; import de.k3b.io.FileNameUtil; +import de.k3b.io.IFile; /** * Manage permission @@ -132,6 +134,10 @@ private static void execRequestRootUri( parent.startActivityForResult(intent, REQUEST_ROOT_DIR); } + @Deprecated + public File getMissingRootDirFileOrNull(String dbgContext, File... dirs) { + return getMissingRootDirFileOrNull(dbgContext, FileFacade.get(dirs)).getFile(); + } /** * * @param dbgContext @@ -139,12 +145,12 @@ private static void execRequestRootUri( * @return null if all permissions are granted or * the root file that has not permissions yet. */ - public File getMissingRootDirFileOrNull(String dbgContext, File... dirs) { + public IFile getMissingRootDirFileOrNull(String dbgContext, IFile... dirs) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { for (int i = dirs.length - 1; i >= 0; i--) { - final File dir = dirs[i]; + final IFile dir = dirs[i]; if (!getDocumentFileTranslator().isKnownRoot(dir)) { - final File anddroidRootDir = FileNameUtil.getAnddroidRootDir(dir); + final IFile anddroidRootDir = FileNameUtil.getAnddroidRootDir(dir); if (DocumentFileTranslator.debugDocFile) { Log.i(TAG, dbgContext + ":" + this.documentFileTranslator + ":getMissingRootDirFileOrNull(" + dir diff --git a/fastlane/fd2fastlane.py b/fastlane/fd2fastlane.py index 189a1f89..dedab701 100644 --- a/fastlane/fd2fastlane.py +++ b/fastlane/fd2fastlane.py @@ -74,7 +74,7 @@ def save_to_wiki_homepage(title, short_description, full_description, android_locale): - if ((len(WIKI_OUT_ROOT) > 0) and (len(android_locale) > 0)): + if ((mylen(WIKI_OUT_ROOT) > 0) and (mylen(android_locale) > 0)): label = f''; homepate_locale = translate_locale(android_locale, LANG_ANDROID_TO_WIKI) filename = homepate_locale + '-home.md' @@ -90,7 +90,7 @@ def save_to_wiki_homepage(title, short_description, full_description, android_lo # does not exist or was autogenerated: overwrite md = generate_wiki_homepage(label, title, short_description, full_description) - # print(f'\t{full_md_path[-10:]}\t{oldContent[:10]}\t{len(oldContent)} {label}') + # print(f'\t{full_md_path[-10:]}\t{oldContent[:10]}\t{mylen(oldContent)} {label}') save_to_file(md, WIKI_OUT_ROOT, filename) @@ -111,7 +111,7 @@ def generate_wiki_homepage(label, title, short_description, full_description): def save_to_app_about(title, short_description, full_description, android_locale): - if (len(APP_OUT_RES_ROOT) > 0) and (len(android_locale) > 0): + if (mylen(APP_OUT_RES_ROOT) > 0) and (mylen(android_locale) > 0): label = f''; dir = os.path.join(APP_OUT_RES_ROOT, "values" + android_locale) filename = "html-pages.xml" @@ -127,7 +127,7 @@ def save_to_app_about(title, short_description, full_description, android_locale # does not exist or was autogenerated: overwrite md = generate_app_about(label, title, short_description, full_description.replace("\"", "\\\"")) - # print(f'\t{full_md_path[-10:]}\t{oldContent[:10]}\t{len(oldContent)} {label}') + # print(f'\t{full_md_path[-10:]}\t{oldContent[:10]}\t{mylen(oldContent)} {label}') save_to_file(md, dir, filename) @@ -165,7 +165,7 @@ def process_translation(fdroid_xml, android_locale): # print(android_locale + '\t' + fastlane_locale + '\t' + fdroid_xml) root = ElementTree.parse(fdroid_xml).getroot() title = getElementText(root, './/string[@name="title"]', 50, fdroid_xml) - if len(DEFAULT_APP_TITLE) > 0 and len(title) > 0 and title.find(DEFAULT_APP_TITLE) < 0: + if mylen(DEFAULT_APP_TITLE) > 0 and mylen(title) > 0 and title.find(DEFAULT_APP_TITLE) < 0: title = DEFAULT_APP_TITLE + " (" + title + ")" short_description = getElementText(root, './/string[@name="short_description"]', 80, @@ -179,7 +179,7 @@ def process_translation(fdroid_xml, android_locale): save_to_file(short_description, cur_fastlane_out_dir, 'short_description.txt') if (full_description is not None): - if len(title) == 0: + if mylen(title) == 0: title = DEFAULT_APP_TITLE html = markdown.markdown(full_description) @@ -192,7 +192,7 @@ def translate_locale(android_locale, locale_map): result_locale = "" if android_locale in locale_map.keys(): result_locale = locale_map[android_locale] - elif (len(android_locale) == 3): + elif (mylen(android_locale) == 3): # if not found: translate '-de' to 'de' result_locale = android_locale[1:] return result_locale @@ -219,12 +219,18 @@ def save_to_file(content, directory_path, filename): def clean_text(text, limit=0, context=''): # remove leading/trailing blanks and string delimiter, unescape String delimiter text = text.strip("\s\"'").replace('\\\'', '\'').replace('\\\"', '\"') - if limit != 0 and len(text) > limit: + if limit != 0 and mylen(text) > limit: print(context + " Warning: Text longer than %d characters, ignoring..." % limit) # text = text[:limit] return text +def mylen(item): + if item is None: + return 0 + return len(item) + + def main(): path = os.path.join(PATH, FD_SRC_PATH_ROOT, 'values*/fdroid.xml') diff --git a/fotolib2/src/main/java/de/k3b/io/FileCommands.java b/fotolib2/src/main/java/de/k3b/io/FileCommands.java index cb0a0fc3..d6a8e7b1 100644 --- a/fotolib2/src/main/java/de/k3b/io/FileCommands.java +++ b/fotolib2/src/main/java/de/k3b/io/FileCommands.java @@ -23,11 +23,7 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Date; @@ -130,36 +126,34 @@ protected boolean canProcessFile(int opCode) { } /** - * @return true if file was deleted or does not exist (any more) + * + * @param sourceFullPath the path of the file that shall be copied including the file name with ending + * @param targetFullPath the path of the file that shall be written to without filename + * + * Copies a file from the sourceFullPath path to the target path. */ - protected boolean deleteFileWithSidecar(File file) { - boolean result = false; - - if (file != null) { - File sidecar = getSidecar(file, false); - if (osFileExists(sidecar)) { - osDeleteFile(sidecar); // dont care if delete was successfull - } - sidecar = getSidecar(file, true); - if (osFileExists(sidecar)) { - osDeleteFile(sidecar); // dont care if delete was successfull - } - - if (osFileExists(file)) { - if (!osDeleteFile(file)) { - log("rem file exists. delete failed : ", file.getAbsolutePath()); - } else { - result = true; // was deleted - } - } else { - log("rem file '", file.getAbsolutePath(), "' does not exist"); - result = true; // it is gone + private static boolean _osFileCopy(IFile targetFullPath, IFile sourceFullPath, FileCommands owner) { + boolean result = true; + try { + result = sourceFullPath.copy(targetFullPath, false); + } catch (Throwable e) { + result = false; + if (owner != null) { + owner.onException(e, "_osFileCopy", sourceFullPath, targetFullPath); } - log(MediaTransactionLogEntryType.DELETE.getCommand(file.getAbsolutePath(),"")); + } + if (LibGlobal.debugEnabledJpg) { + logger.info("osFileCopy '" + sourceFullPath + + "' => '" + targetFullPath + "' success=" + result); } return result; } + @Deprecated + protected boolean deleteFileWithSidecar(File file) { + return deleteFileWithSidecar(FileFacade.convert(file)); + } + /** * apply changes in exifChanges to all images in selectedFiles. * @return number of changed files. @@ -239,10 +233,93 @@ int moveOrCopyFilesTo(boolean move, return result; } - /** does the copying and/or apply exif changes. also used by unittesting */ + /** + * @return true if file was deleted or does not exist (any more) + */ + protected boolean deleteFileWithSidecar(IFile file) { + boolean result = false; + + if (file != null) { + IFile sidecar = getSidecar(file, false); + if (osFileExists(sidecar)) { + osDeleteFile(sidecar); // dont care if delete was successfull + } + sidecar = getSidecar(file, true); + if (osFileExists(sidecar)) { + osDeleteFile(sidecar); // dont care if delete was successfull + } + + if (osFileExists(file)) { + if (!osDeleteFile(file)) { + log("rem file exists. delete failed : ", file.getAbsolutePath()); + } else { + result = true; // was deleted + } + } else { + log("rem file '", file.getAbsolutePath(), "' does not exist"); + result = true; // it is gone + } + log(MediaTransactionLogEntryType.DELETE.getCommand(file.getAbsolutePath(), "")); + } + return result; + } + + @Deprecated protected int moveOrCopyFiles(final boolean move, String what, PhotoPropertiesDiffCopy exifChanges, SelectedFiles fotos, File[] destFiles, IProgessListener progessListener) { + return moveOrCopyFiles(move, what, exifChanges, fotos, FileFacade.get(destFiles), progessListener); + } + + protected TransactionLoggerBase createTransactionLogger(long now) { + return new TransactionLoggerBase(this, now); + } + + private PhotoAutoprocessingDto getPhotoAutoprocessingDto(File destDirFolder) { + PhotoAutoprocessingDto autoProccessData = null; + try { + autoProccessData = new PhotoAutoprocessingDto().load(destDirFolder); + } catch (IOException e) { + log("cannot load .apm file for '", destDirFolder, "'. ", e.getMessage()); + autoProccessData = null; + } + return autoProccessData; + } + + public PhotoPropertiesBulkUpdateService createWorkflow(TransactionLoggerBase logger, String dbgContext) { + return new PhotoPropertiesBulkUpdateService(logger); + } + + private File[] createDestFiles(IFileNameProcessor renameProcessor, File destDirFolder, Date[] datesLastModified, File... sourceFiles) { + File[] result = new File[sourceFiles.length]; + + int pos = 0; + File destFile; + for (File srcFile : sourceFiles) { + if (renameProcessor != null) { + destFile = renameProcessor.getNextFile(srcFile, getRenameSourceFileDate(srcFile, datesLastModified, pos), -1); + } else { + destFile = new File(destDirFolder, srcFile.getName()); + } + result[pos++] = destFile; + } + + return result; + } + + private Date getRenameSourceFileDate(File srcFile, Date[] datesLastModified, int pos) { + if ((datesLastModified != null) && (pos >= 0) && (pos < datesLastModified.length)) { + return datesLastModified[pos]; + } + return new Date(srcFile.lastModified()); + } + + /** + * does the copying and/or apply exif changes. also used by unittesting + */ + protected int moveOrCopyFiles(final boolean move, String what, PhotoPropertiesDiffCopy exifChanges, + SelectedFiles fotos, IFile[] destFiles, + IProgessListener progessListener) { long startTimestamp = 0; if (LibGlobal.debugEnabledJpgMetaIo) { startTimestamp = new Date().getTime(); @@ -259,7 +336,7 @@ protected int moveOrCopyFiles(final boolean move, String what, PhotoPropertiesDi int fileCount = destFiles.length; Long[] ids = fotos.getIds(); - File[] sourceFiles = fotos.getFiles(); + IFile[] sourceFiles = fotos.getIFiles(); mModifiedSrcFiles = (move) ? new ArrayList() : null; mModifiedDestFiles = new ArrayList(); @@ -279,8 +356,8 @@ protected int moveOrCopyFiles(final boolean move, String what, PhotoPropertiesDi boolean sameFile; while (pos < fileCount) { - File sourceFile = FileUtils.tryGetCanonicalFile(sourceFiles[pos]); - File destFile = FileUtils.tryGetCanonicalFile(destFiles[pos]); + IFile sourceFile = sourceFiles[pos]; + IFile destFile = destFiles[pos].getCanonicalFile(); Long id = ids[pos]; boolean deleteOriginalAfterFinish = move; @@ -290,7 +367,7 @@ protected int moveOrCopyFiles(final boolean move, String what, PhotoPropertiesDi if (!onProgress(itemcount, maxCount, (sourceFile == null) ? null : sourceFile.toString())) break; } - File destRenamed; + IFile destRenamed; sameFile = (sourceFile != null) && sourceFile.equals(destFile); if ((exifChanges != null) && sameFile) { // copy/move with exif changes ==> exif changes only @@ -299,8 +376,8 @@ protected int moveOrCopyFiles(final boolean move, String what, PhotoPropertiesDi destRenamed = renameDuplicate(destFile); } - final String sourcePath = FileUtils.tryGetCanonicalPath(sourceFile, null); - final String destPath = FileUtils.tryGetCanonicalPath(destRenamed, null); + final String sourcePath = sourceFile.getCanonicalPath(); + final String destPath = destRenamed.getCanonicalPath(); if ((sourcePath != null) && (destPath != null)) { if (exifChanges == null) { @@ -308,18 +385,18 @@ protected int moveOrCopyFiles(final boolean move, String what, PhotoPropertiesDi if (osFileMoveOrCopy(move, destRenamed, sourceFile)) itemCount++; - File sourceSidecar = getSidecar(sourceFile, false); + IFile sourceSidecar = getSidecar(sourceFile, false); if (osFileExists(sourceSidecar)) { - File destSidecar = getSidecar(destRenamed, false); + IFile destSidecar = getSidecar(destRenamed, false); if (osFileMoveOrCopy(move, destSidecar, sourceSidecar)) itemCount++; } sourceSidecar = getSidecar(sourceFile, true); if (osFileExists(sourceSidecar)) { - File destSidecar = getSidecar(destRenamed, true); + IFile destSidecar = getSidecar(destRenamed, true); if (osFileMoveOrCopy(move, destSidecar, sourceSidecar)) itemCount++; } - addTransactionLog(id, sourceFile.getPath(), now, moveOrCopyCommand, destFile.getPath()); + addTransactionLog(id, sourceFile.getAbsolutePath(), now, moveOrCopyCommand, destFile.getAbsolutePath()); } else { // else move/copy with simultanious exif changes PhotoPropertiesDiffCopy mediaDiffCopy = exifChanges; // new style move/copy image with sidecarfile(s) with exif autoprocessing @@ -327,7 +404,8 @@ protected int moveOrCopyFiles(final boolean move, String what, PhotoPropertiesDi // for the log the file has already been copied/moved logger.set(id, sourcePath); - PhotoPropertiesUpdateHandler exifProcessor = createWorkflow(logger, what).applyChanges(sourceFile, destPath, id, move, mediaDiffCopy); + PhotoPropertiesUpdateHandler exifProcessor = createWorkflow(logger, what) + .applyChanges(sourceFile, destPath, id, move, mediaDiffCopy); if (exifProcessor == null) break; // error @@ -339,7 +417,7 @@ protected int moveOrCopyFiles(final boolean move, String what, PhotoPropertiesDi String modifiedOutPath = exifProcessor.getAbsoluteJpgOutPath(); if (null != modifiedOutPath) { // destFile might have renamed it-s extension for private images - destFile = new File(modifiedOutPath); + destFile = FileFacade.convert(new File(modifiedOutPath)); sameFile = (sourceFile != null) && sourceFile.equals(destFile); } @@ -374,51 +452,15 @@ protected int moveOrCopyFiles(final boolean move, String what, PhotoPropertiesDi return itemCount; } - protected TransactionLoggerBase createTransactionLogger(long now) { - return new TransactionLoggerBase(this, now); - } - - private PhotoAutoprocessingDto getPhotoAutoprocessingDto(File destDirFolder) { - PhotoAutoprocessingDto autoProccessData = null; - try { - autoProccessData = new PhotoAutoprocessingDto().load(destDirFolder); - } catch (IOException e) { - log("cannot load .apm file for '", destDirFolder, "'. ", e.getMessage()); - autoProccessData = null; - } - return autoProccessData; - } - - public PhotoPropertiesBulkUpdateService createWorkflow(TransactionLoggerBase logger, String dbgContext) { - return new PhotoPropertiesBulkUpdateService(logger); - } - - private File[] createDestFiles(IFileNameProcessor renameProcessor, File destDirFolder, Date[] datesLastModified, File... sourceFiles) { - File[] result = new File[sourceFiles.length]; - - int pos = 0; - File destFile; - for(File srcFile : sourceFiles) { - if (renameProcessor != null) { - destFile = renameProcessor.getNextFile(srcFile, getRenameSourceFileDate(srcFile, datesLastModified, pos), -1); - } else { - destFile = new File(destDirFolder, srcFile.getName()); - } - result[pos++] = destFile; - } - - return result; - } - - private Date getRenameSourceFileDate(File srcFile, Date[] datesLastModified, int pos) { - if ((datesLastModified != null) && (pos >= 0) && (pos < datesLastModified.length)) { - return datesLastModified[pos]; - } - return new Date(srcFile.lastModified()); + @Deprecated + protected boolean osFileMoveOrCopy(boolean move, File dest, File source) { + return osFileMoveOrCopy(move, FileFacade.convert(dest), FileFacade.convert(source)); } - /** executes os specific move or copy operation and updates the list of modified files */ - protected boolean osFileMoveOrCopy(boolean move, File dest, File source) { + /** + * executes os specific move or copy operation and updates the list of modified files + */ + protected boolean osFileMoveOrCopy(boolean move, IFile dest, IFile source) { boolean result = false; long fileTime = source.lastModified(); @@ -438,15 +480,22 @@ protected boolean osFileMoveOrCopy(boolean move, File dest, File source) { return result; } - private void addProcessedFiles(boolean move, File dest, File source) { + private void addProcessedFiles(boolean move, IFile dest, IFile source) { mModifiedDestFiles.add(dest.getAbsolutePath()); if (move) { mModifiedSrcFiles.add(source.getAbsolutePath()); } } - /** can be replaced by mock/stub in unittests */ + @Deprecated protected boolean osFileMove(File dest, File source) { + return osFileMove(FileFacade.convert(dest), FileFacade.convert(source)); + } + + /** + * can be replaced by mock/stub in unittests + */ + protected boolean osFileMove(IFile dest, IFile source) { if (osRenameTo(dest, source)) { // move within same mountpoint if (LibGlobal.debugEnabledJpg) { @@ -479,19 +528,18 @@ && osFileCopy(dest, source)) { return false; } + @Deprecated protected boolean osRenameTo(File dest, File source) { - return this.fileApi.osRenameTo(dest, source); + return osRenameTo(FileFacade.convert(dest), FileFacade.convert(source)); } - /** - * - * @param sourceFullPath the path of the file that shall be copied including the file name with ending - * @param targetFullPath the path of the file that shall be written to without filename - * - * Copies a file from the sourceFullPath path to the target path. - */ + protected boolean osRenameTo(IFile dest, IFile source) { + return source.renameTo(dest); + } + + @Deprecated protected boolean osFileCopy(File targetFullPath, File sourceFullPath) { - return _osFileCopy(targetFullPath, sourceFullPath, this); + return osFileCopy(FileFacade.convert(targetFullPath), FileFacade.convert(sourceFullPath)); } /** @@ -501,41 +549,31 @@ protected boolean osFileCopy(File targetFullPath, File sourceFullPath) { * * Copies a file from the sourceFullPath path to the target path. */ - private static boolean _osFileCopy(File targetFullPath, File sourceFullPath, FileCommands owner) { - boolean result = true; - - FileChannel in = null; - FileChannel out = null; - try { - in = new FileInputStream(sourceFullPath).getChannel(); - out = new FileOutputStream(targetFullPath).getChannel(); - long size = in.size(); - MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0, size); - out.write(buf); - } catch (Throwable e) { - result = false; - if (owner != null) { - owner.onException(e, "_osFileCopy", sourceFullPath, targetFullPath); - } - } finally { - FileUtils.close(in,"_osFileCopy-close"); - FileUtils.close(out,"_osFileCopy-close"); - } - if (LibGlobal.debugEnabledJpg) { - logger.info("osFileCopy '" + sourceFullPath - + "' => '" + targetFullPath + "' success=" + result); - } - return result; + protected boolean osFileCopy(IFile targetFullPath, IFile sourceFullPath) { + return _osFileCopy(targetFullPath, sourceFullPath, this); } + @Deprecated protected boolean osDeleteFile(File file) { - final boolean result = fileApi.osDeleteFile(file); + return osDeleteFile(FileFacade.convert(file)); + } + + protected boolean osDeleteFile(IFile file) { + final boolean result = file.delete(); if (LibGlobal.debugEnabledJpg) logger.info("osDeleteFile '" + file + "' success=" + result); return result; } /** to be replaced by mock/stub in unittests */ + @Deprecated protected boolean osCreateDirIfNeccessary(File destDirFolder) { + return osCreateDirIfNeccessary(FileFacade.convert(destDirFolder)); + } + + /** + * to be replaced by mock/stub in unittests + */ + protected boolean osCreateDirIfNeccessary(IFile destDirFolder) { return destDirFolder.mkdirs() || destDirFolder.isDirectory(); } diff --git a/fotolib2/src/main/java/de/k3b/io/FileFacade.java b/fotolib2/src/main/java/de/k3b/io/FileFacade.java index 404b34d2..3c746f73 100644 --- a/fotolib2/src/main/java/de/k3b/io/FileFacade.java +++ b/fotolib2/src/main/java/de/k3b/io/FileFacade.java @@ -35,8 +35,15 @@ * add support for Android DocumentFile */ public class FileFacade implements IFile { + private static Converter fileFacade = new Converter() { + @Override + public IFile convert(File file) { + return new FileFacade(file); + } + }; private File file; + public FileFacade(File file) { this.file = file; } @@ -53,15 +60,34 @@ public FileFacade(String parent, String newFolderName) { this(new File(parent, newFolderName)); } - public static FileFacade[] get(File[] files) { - FileFacade f[] = new FileFacade[files.length]; + public static IFile[] get(File[] files) { + IFile f[] = new FileFacade[files.length]; for (int i = 0; i < files.length; i++) { - f[i] = new FileFacade(files[i]); + f[i] = convert(files[i]); } return f; } + /** + * gets existing file from parent or create it if not found + */ + public static IFile getOrCreateChild(IFile parent, String name, String mime) { + IFile result = parent.findExisting(name); + if (result == null) { + result = parent.create(name, mime); + } + return result; + } + + public static IFile convert(File file) { + return fileFacade.convert(file); + } + + public static void setFileFacade(Converter fileFacade) { + FileFacade.fileFacade = fileFacade; + } + @Deprecated @Override public boolean renameTo(IFile newName) { @@ -97,7 +123,7 @@ public boolean exists() { public IFile findExisting(String name) { final File candidate = new File(this.file, name); if (candidate.exists()) { - return new FileFacade(candidate); + return convert(candidate); } return null; } @@ -139,7 +165,7 @@ public String getAbsolutePath() { @Override public IFile getCanonicalFile() { - return new FileFacade(FileUtils.tryGetCanonicalFile(file)); + return convert(FileUtils.tryGetCanonicalFile(file)); } @Override @@ -149,7 +175,7 @@ public String getCanonicalPath() { @Override public IFile getParentFile() { - return new FileFacade(file.getParentFile()); + return convert(file.getParentFile()); } @Override @@ -167,6 +193,11 @@ public long lastModified() { return file.lastModified(); } + @Override + public void setLastModified(long fileTime) { + file.setLastModified(fileTime); + } + @Override public boolean mkdirs() { return file.mkdirs(); @@ -228,7 +259,7 @@ public String getMime() { @Override public IFile create(String name, String mime) { - return new FileFacade(new File(file, name)); + return convert(new File(file, name)); } @Override @@ -236,7 +267,7 @@ public String toString() { return String.format("%s: %s", this.getClass().getSimpleName(), file.getAbsoluteFile()); } - protected File getFile() { + public File getFile() { return file; } diff --git a/fotolib2/src/main/java/de/k3b/io/FileProcessor.java b/fotolib2/src/main/java/de/k3b/io/FileProcessor.java index 71b885c6..155faa2a 100644 --- a/fotolib2/src/main/java/de/k3b/io/FileProcessor.java +++ b/fotolib2/src/main/java/de/k3b/io/FileProcessor.java @@ -28,35 +28,48 @@ public class FileProcessor extends FileCommandLogger implements IFileCommandLogger { private static final String EXT_SIDECAR = ".xmp"; + /// TODO what is mime for XMP + private static final String XMP_MINE = "*/*"; + /** if not null: all logging goes through this */ private IFileCommandLogger internalLogger = null; // private static final String LOG_FILE_ENCODING = "UTF-8"; - /** can be replaced by mock/stub in unittests */ - public boolean osFileExists(File file) { - return file.exists(); - } - protected boolean fileOrSidecarExists(File file) { + @Deprecated + public static boolean isSidecar(File file) { if (file == null) return false; - - return osFileExists(file) || osFileExists(FileCommands.getSidecar(file, false)) || osFileExists(FileCommands.getSidecar(file, true)); + return isSidecar(file.getName()); } - public static boolean isSidecar(File file) { + + public static boolean isSidecar(IFile file) { if (file == null) return false; - return isSidecar(file.getAbsolutePath()); + return isSidecar(file.getName()); } - public static boolean isSidecar(String name) { - if (name == null) return false; - return name.toLowerCase().endsWith(EXT_SIDECAR); + @Deprecated + public static IFile getSidecar(File file, boolean longFormat) { + return getSidecar(FileFacade.convert(file), longFormat); } - public static File getSidecar(File file, boolean longFormat) { + public static IFile getSidecar(IFile file, boolean longFormat) { if (file == null) return null; - return getSidecar(file.getAbsolutePath(), longFormat); + String name = file.getName(); + return getSidecar(file.getParentFile(), name, longFormat); + } + + public static XmpFile getSidecar(IFile parent, String name, boolean longFormat) { + XmpFile result; + if (longFormat) { + result = new XmpFile(FileFacade.getOrCreateChild(parent, name + EXT_SIDECAR, XMP_MINE), longFormat); + } else { + result = new XmpFile(FileFacade.getOrCreateChild(parent, FileUtils.replaceExtension(name, EXT_SIDECAR), XMP_MINE), longFormat); + } + return result; + } + @Deprecated public static XmpFile getSidecar(String absolutePath, boolean longFormat) { XmpFile result; if (longFormat) { @@ -67,28 +80,40 @@ public static XmpFile getSidecar(String absolutePath, boolean longFormat) { return result; } - public static class XmpFile extends File { - /** true: file.jpg.xmp; false: file.xmp */ - private final boolean longFormat; - private boolean hasAlsoOtherFormat = false; + public static boolean isSidecar(String name) { + if (name == null) return false; + return name.toLowerCase().endsWith(EXT_SIDECAR); + } - public XmpFile(String absolutePath, boolean longFormat) { - super(absolutePath); - this.longFormat = longFormat; - } + /** + * can be replaced by mock/stub in unittests + */ + @Deprecated + public boolean osFileExists(File file) { + return osFileExists(FileFacade.convert(file)); + } - /** true: file.jpg.xmp; false: file.xmp */ - public boolean isLongFormat() { - return longFormat; - } + public boolean osFileExists(IFile file) { + return file.exists(); + } - public boolean isHasAlsoOtherFormat() { - return hasAlsoOtherFormat; - } + @Deprecated + protected boolean fileOrSidecarExists(File file) { + return fileOrSidecarExists(FileFacade.convert(file)); + } - public void setHasAlsoOtherFormat(boolean hasAlsoOtherFormat) { - this.hasAlsoOtherFormat = hasAlsoOtherFormat; - } + protected boolean fileOrSidecarExists(IFile file) { + if (file == null) return false; + + IFile parent = file.getParentFile(); + String name = file.getName(); + return file.exists() || FileCommands.getSidecar(parent, name, false).exists() + || FileCommands.getSidecar(parent, name, true).exists(); + } + + @Deprecated + public File renameDuplicate(File file) { + return FileFacade.convert(file).getFile(); } public static XmpFile getExistingSidecarOrNull(String absolutePath) { @@ -116,14 +141,16 @@ public static XmpFile getExistingSidecarOrNull(String absolutePath, boolean long /** * @return file if rename is not neccessary else File with new name */ - public File renameDuplicate(File file) { + public IFile renameDuplicate(IFile file) { if (!fileOrSidecarExists(file)) { // rename is not neccessary return file; } + IFile parent = file.getParentFile(); - String filename = file.getAbsolutePath(); + String mime = file.getMime(); + String filename = file.getName(); String extension = ")"; int extensionPosition = filename.lastIndexOf("."); if (extensionPosition >= 0) { @@ -133,16 +160,53 @@ public File renameDuplicate(File file) { int id = 0; while (true) { id++; - String candidatePath = filename + id + extension; - File candidate = new File(candidatePath); + String candidateName = filename + id + extension; + IFile candidate = parent.create(candidateName, mime); if (!fileOrSidecarExists(candidate)) { - log("rem renamed from '", filename, "' to '", candidatePath,"'"); + log("rem renamed from '", filename, "' to '", candidateName,"'"); return candidate; } } } + public static class XmpFile extends FileWrapper { + /** + * true: file.jpg.xmp; false: file.xmp + */ + private final boolean longFormat; + private boolean hasAlsoOtherFormat = false; + + public XmpFile(IFile parent, String name, String mime, boolean longFormat) { + this(FileFacade.getOrCreateChild(parent, name, mime), longFormat); + } + + @Deprecated + public XmpFile(String absolutePath, boolean longFormat) { + this(FileFacade.convert(new File(absolutePath)), longFormat); + } + + public XmpFile(IFile file, boolean longFormat) { + super(file); + this.longFormat = longFormat; + } + + /** + * true: file.jpg.xmp; false: file.xmp + */ + public boolean isLongFormat() { + return longFormat; + } + + public boolean isHasAlsoOtherFormat() { + return hasAlsoOtherFormat; + } + + public void setHasAlsoOtherFormat(boolean hasAlsoOtherFormat) { + this.hasAlsoOtherFormat = hasAlsoOtherFormat; + } + } + /** if not null: all logging goes through this */ public IFileCommandLogger getInternalLogger() { return internalLogger; diff --git a/fotolib2/src/main/java/de/k3b/io/FileUtils.java b/fotolib2/src/main/java/de/k3b/io/FileUtils.java index fb7fd05b..b7ab68ea 100644 --- a/fotolib2/src/main/java/de/k3b/io/FileUtils.java +++ b/fotolib2/src/main/java/de/k3b/io/FileUtils.java @@ -28,9 +28,6 @@ import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; @@ -59,8 +56,13 @@ public static String readFile(InputStream file) throws IOException { return internalReadFile(new BufferedReader(new InputStreamReader(file)), file); } + @Deprecated public static String readFile(File file) throws IOException { - return internalReadFile(new BufferedReader(new FileReader(file)), file); + return readFile(FileFacade.convert(file)); + } + + public static String readFile(IFile file) throws IOException { + return internalReadFile(new BufferedReader(new InputStreamReader(file.openInputStream())), file); } public static String readFile(InputStream is, byte[] buffer) throws IOException { @@ -76,9 +78,13 @@ public static String readFile(InputStream is, byte[] buffer) throws IOException * helper to copy stream-data */ public static void copyStream(OutputStream outputStream, InputStream inputStream, byte[] buffer) throws IOException { - for (int read = inputStream.read(buffer); read > -1; read = inputStream - .read(buffer)) { - outputStream.write(buffer, 0, read); + try { + for (int read = inputStream.read(buffer); read > -1; read = inputStream + .read(buffer)) { + outputStream.write(buffer, 0, read); + } + } finally { + close(inputStream, null); } } @@ -86,12 +92,15 @@ public static String internalReadFile(BufferedReader br, Object source) throws I StringBuilder sb = new StringBuilder(); String line = br.readLine(); - while (line != null) { - sb.append(line); - sb.append("\n"); - line = br.readLine(); + try { + while (line != null) { + sb.append(line); + sb.append("\n"); + line = br.readLine(); + } + } finally { + close(br, source); } - close(br, source); return sb.toString(); } @@ -249,13 +258,17 @@ public static void delete(String fileName, String fileExt) { delete(file, fileExt); } - // Delete the file or if it's a directory, all files in the directory public static void delete(File file, final String fileExt) { + delete(FileFacade.convert(file), fileExt); + } + + // Delete the file or if it's a directory, all files in the directory + public static void delete(IFile file, final String fileExt) { if (file.exists()) { //check if the file is a directory if (file.isDirectory()) { - File[] files = file.listFiles(); - for(File f:files){ + IFile[] files = file.listFiles(); + for (IFile f : files) { //call deletion of file individually delete(f, fileExt); } @@ -284,14 +297,19 @@ public static void copyReplace(String sourcePath, String destinationPath, copyReplace(new File(sourcePath), new File(destinationPath), deleteOriginalAfterFinish, what); } + @Deprecated public static void copyReplace(File inFile, File outFile, boolean deleteOriginalAfterFinish, String what) throws IOException { + copyReplace(FileFacade.convert(inFile), FileFacade.convert(outFile), deleteOriginalAfterFinish, what); + } + + public static void copyReplace(IFile inFile, IFile outFile, boolean deleteOriginalAfterFinish, String what) throws IOException { if (logger.isDebugEnabled()) { logger.debug(DBG_CONTEXT + what + (deleteOriginalAfterFinish ? "-move" : "-copy") + ": " + inFile + " ==> " + outFile); } InputStream sourceStream = null; try { - sourceStream = new FileInputStream(inFile); + sourceStream = inFile.openInputStream(); copyReplace(sourceStream, outFile); if(deleteOriginalAfterFinish && inFile.exists()) inFile.delete(); @@ -300,10 +318,15 @@ public static void copyReplace(File inFile, File outFile, boolean deleteOriginal } } + @Deprecated public static void copyReplace(InputStream sourceStream, File destinationFile) throws IOException { + copyReplace(sourceStream, FileFacade.convert(destinationFile)); + } + + public static void copyReplace(InputStream sourceStream, IFile destinationFile) throws IOException { if (destinationFile.exists()) destinationFile.delete(); destinationFile.getParentFile().mkdirs(); - FileOutputStream result = new FileOutputStream(destinationFile); + OutputStream result = destinationFile.openOutputStream(); FileUtils.copy(sourceStream, result); result.flush(); FileUtils.close(result, destinationFile); @@ -330,21 +353,32 @@ public static String fixPath(String path) { return path; } + @Deprecated public static File getFirstExistingDir(File root) { + return getFirstExistingDir(FileFacade.convert(root)).getFile(); + } + + public static IFile getFirstExistingDir(IFile root) { while ((root != null) && (!root.exists() || !root.isDirectory())) { root = root.getParentFile(); } return root; } + @Deprecated public static File getFirstNonExistingFile(File parentDir, String newFilePrefix, int number, String newFileSuffix) { + return getFirstNonExistingFile(FileFacade.convert(parentDir), newFilePrefix, number, newFileSuffix).getFile(); + } + + public static IFile getFirstNonExistingFile(IFile parentDir, String newFilePrefix, int number, String newFileSuffix) { if (parentDir == null) return null; parentDir.mkdirs(); - File candidate = new File(parentDir, newFilePrefix + newFileSuffix); + final String mime = "*/*"; + IFile candidate = parentDir.create(newFilePrefix + newFileSuffix, mime); while (candidate.exists()) { number ++; - candidate = new File(parentDir, newFilePrefix + number + newFileSuffix); + candidate = parentDir.create(newFilePrefix + number + newFileSuffix, mime); } return candidate; } diff --git a/fotolib2/src/main/java/de/k3b/io/FileWrapper.java b/fotolib2/src/main/java/de/k3b/io/FileWrapper.java new file mode 100644 index 00000000..57d2d638 --- /dev/null +++ b/fotolib2/src/main/java/de/k3b/io/FileWrapper.java @@ -0,0 +1,150 @@ +package de.k3b.io; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class FileWrapper implements IFile { + private final IFile child; + + public FileWrapper(IFile child) { + this.child = child; + } + + @Override + public boolean renameTo(IFile newName) { + return child.renameTo(newName); + } + + @Override + public boolean renameTo(String newName) { + return child.renameTo(newName); + } + + @Override + public boolean delete() { + return child.delete(); + } + + @Override + public boolean exists() { + return child.exists(); + } + + @Override + public IFile findExisting(String name) { + return child.findExisting(name); + } + + @Override + public boolean canWrite() { + return child.canWrite(); + } + + @Override + public boolean canRead() { + return child.canRead(); + } + + @Override + public boolean isFile() { + return child.isFile(); + } + + @Override + public boolean isDirectory() { + return child.isDirectory(); + } + + @Override + public boolean isHidden() { + return child.isHidden(); + } + + @Override + public boolean isAbsolute() { + return child.isAbsolute(); + } + + @Override + public String getAbsolutePath() { + return child.getAbsolutePath(); + } + + @Override + public IFile getCanonicalFile() { + return child.getCanonicalFile(); + } + + @Override + public String getCanonicalPath() { + return child.getCanonicalPath(); + } + + @Override + public IFile getParentFile() { + return child.getParentFile(); + } + + @Override + public String getParent() { + return child.getParent(); + } + + @Override + public String getName() { + return child.getName(); + } + + @Override + public void setLastModified(long fileTime) { + child.setLastModified(fileTime); + } + + @Override + public long lastModified() { + return child.lastModified(); + } + + @Override + public boolean mkdirs() { + return child.mkdirs(); + } + + @Override + public IFile[] listFiles() { + return child.listFiles(); + } + + @Override + public boolean copy(IFile targetFullPath, boolean deleteSourceWhenSuccess) throws IOException { + return child.copy(targetFullPath, deleteSourceWhenSuccess); + } + + @Override + public OutputStream openOutputStream() throws FileNotFoundException { + return child.openOutputStream(); + } + + @Override + public InputStream openInputStream() throws FileNotFoundException { + return child.openInputStream(); + } + + @Override + public String getMime() { + return child.getMime(); + } + + @Override + public IFile create(String name, String mime) { + return child.create(name, mime); + } + + @Override + public File getFile() { + return child.getFile(); + } +} diff --git a/fotolib2/src/main/java/de/k3b/io/IFile.java b/fotolib2/src/main/java/de/k3b/io/IFile.java index c96708e3..df24c5c4 100644 --- a/fotolib2/src/main/java/de/k3b/io/IFile.java +++ b/fotolib2/src/main/java/de/k3b/io/IFile.java @@ -19,6 +19,7 @@ */ package de.k3b.io; +import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -67,6 +68,7 @@ public interface IFile { String getName(); + void setLastModified(long fileTime); long lastModified(); boolean mkdirs(); @@ -85,4 +87,6 @@ public interface IFile { * overwrite existing */ IFile create(String name, String mime); + + File getFile(); } diff --git a/fotolib2/src/main/java/de/k3b/io/collections/SelectedFiles.java b/fotolib2/src/main/java/de/k3b/io/collections/SelectedFiles.java index cafbe920..21206223 100644 --- a/fotolib2/src/main/java/de/k3b/io/collections/SelectedFiles.java +++ b/fotolib2/src/main/java/de/k3b/io/collections/SelectedFiles.java @@ -22,6 +22,9 @@ import java.io.File; import java.util.Date; +import de.k3b.io.FileFacade; +import de.k3b.io.IFile; + /** * The Multi-selection data for all photo commands. * Unmodifyable list of file names and optional their IDs. @@ -105,6 +108,11 @@ public static File[] getFiles(String[] fileNames) { return result; } + public IFile[] getIFiles() { + return FileFacade.get(getFiles()); + } + + @Deprecated public File[] getFiles() { return SelectedFiles.getFiles(getFileNames()); } diff --git a/fotolib2/src/main/java/de/k3b/media/ExifInterface.java b/fotolib2/src/main/java/de/k3b/media/ExifInterface.java index 44283391..230e5ac1 100644 --- a/fotolib2/src/main/java/de/k3b/media/ExifInterface.java +++ b/fotolib2/src/main/java/de/k3b/media/ExifInterface.java @@ -50,7 +50,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import de.k3b.io.Converter; import de.k3b.io.FileFacade; import de.k3b.io.IFile; @@ -69,12 +68,6 @@ public class ExifInterface { private static final Logger logger = LoggerFactory.getLogger(LOG_TAG); private static final boolean DEBUG_INTERNAL = false; - protected static Converter fileFacade = new Converter() { - @Override - public IFile convert(File file) { - return new FileFacade(file); - } - }; // public to allow global settings to enable/disable public static boolean DEBUG = false; @@ -1132,7 +1125,7 @@ public ExifInterface(String filename, InputStream in) throws IOException { if (filename == null) { throw new IllegalArgumentException("filename cannot be null"); } - mExifFile = (filename != null) ? fileFacade.convert(new File(filename)) : null; + mExifFile = (filename != null) ? FileFacade.convert(new File(filename)) : null; if (in == null) { InputStream inputStream = null; inputStream = createInputStream(mExifFile); @@ -1498,7 +1491,7 @@ public void saveAttributes() throws IOException { */ @Deprecated public void saveAttributes(File inFile, File outFile, boolean deleteInFileOnFinish) throws IOException { - saveAttributes(fileFacade.convert(inFile), fileFacade.convert(outFile), deleteInFileOnFinish); + saveAttributes(FileFacade.convert(inFile), FileFacade.convert(outFile), deleteInFileOnFinish); } public void saveAttributes(IFile inFile, IFile outFile, boolean deleteInFileOnFinish) throws IOException { @@ -1621,7 +1614,7 @@ public byte[] getThumbnail(File inFile) { if (mThumbnailBytes != null) { return mThumbnailBytes; } - return getThumbnail(fileFacade.convert(inFile)); + return getThumbnail(FileFacade.convert(inFile)); } public byte[] getThumbnail(IFile inFile) { diff --git a/fotolib2/src/main/java/de/k3b/media/ExifInterfaceEx.java b/fotolib2/src/main/java/de/k3b/media/ExifInterfaceEx.java index 324e75b7..e9ccf319 100644 --- a/fotolib2/src/main/java/de/k3b/media/ExifInterfaceEx.java +++ b/fotolib2/src/main/java/de/k3b/media/ExifInterfaceEx.java @@ -35,6 +35,7 @@ import java.util.TimeZone; import de.k3b.LibGlobal; +import de.k3b.io.FileFacade; import de.k3b.io.IFile; import de.k3b.io.ListUtils; import de.k3b.io.VISIBILITY; @@ -139,7 +140,7 @@ protected boolean deleteFile(IFile file) { */ @Deprecated protected void fixDateTakenIfNeccessary(File inFile) { - fixDateTakenIfNeccessary(fileFacade.convert(inFile)); + fixDateTakenIfNeccessary(FileFacade.convert(inFile)); } protected void fixDateTakenIfNeccessary(IFile inFile) { @@ -174,7 +175,7 @@ public String getPath() { @Override public IPhotoProperties setPath(String filePath) { - mExifFile = (filePath != null) ? fileFacade.convert(new File(filePath)) : null; + mExifFile = (filePath != null) ? FileFacade.convert(new File(filePath)) : null; if (xmpExtern != null) xmpExtern.setPath(filePath); return this; } @@ -455,7 +456,7 @@ private void loadLatLon() { */ @Deprecated public void setFilelastModified(File file) { - setFilelastModified(fileFacade.convert(file)); + setFilelastModified(FileFacade.convert(file)); } /** when xmp sidecar file was last modified or 0 */ diff --git a/fotolib2/src/main/java/de/k3b/media/PhotoProperties2ExistingFileSaver.java b/fotolib2/src/main/java/de/k3b/media/PhotoProperties2ExistingFileSaver.java index 6460e64f..b1b7de31 100644 --- a/fotolib2/src/main/java/de/k3b/media/PhotoProperties2ExistingFileSaver.java +++ b/fotolib2/src/main/java/de/k3b/media/PhotoProperties2ExistingFileSaver.java @@ -2,13 +2,16 @@ import java.io.File; +import de.k3b.io.FileFacade; import de.k3b.io.FileProcessor; +import de.k3b.io.IFile; import de.k3b.io.IItemSaver; /** Translates every affected file (jpg/xmp) of {@link #save(IPhotoProperties)} to fileSaver.save(File) */ public class PhotoProperties2ExistingFileSaver implements IItemSaver { - private final IItemSaver fileSaver; - public PhotoProperties2ExistingFileSaver(IItemSaver fileSaver) { + private final IItemSaver fileSaver; + + public PhotoProperties2ExistingFileSaver(IItemSaver fileSaver) { this.fileSaver = fileSaver; } @@ -17,7 +20,7 @@ public boolean save(IPhotoProperties item) { if (item != null) { String path = item.getPath(); if (path != null) { - return saveFiles(new File(path), + return saveFiles(FileFacade.convert(new File(path)), FileProcessor.getExistingSidecarOrNull(path, true), FileProcessor.getExistingSidecarOrNull(path, false)) > 0; } @@ -25,9 +28,9 @@ public boolean save(IPhotoProperties item) { return false; } - private int saveFiles(File... files) { + private int saveFiles(IFile... files) { int processed = 0; - for (File f: files) { + for (IFile f : files) { if ((f != null) && (f.exists()) && f.canRead() && this.fileSaver.save(f)) { processed++; } diff --git a/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesBulkUpdateService.java b/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesBulkUpdateService.java index 23768493..d61eb293 100644 --- a/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesBulkUpdateService.java +++ b/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesBulkUpdateService.java @@ -29,7 +29,9 @@ import java.util.List; import de.k3b.LibGlobal; +import de.k3b.io.FileFacade; import de.k3b.io.FileProcessor; +import de.k3b.io.IFile; import de.k3b.io.VISIBILITY; import de.k3b.transactionlog.TransactionLoggerBase; @@ -42,7 +44,7 @@ public class PhotoPropertiesBulkUpdateService { private static final Logger logger = LoggerFactory.getLogger(LibGlobal.LOG_TAG); private final TransactionLoggerBase transactionLogger; - private StringBuilder debugExif(StringBuilder sb, String context, PhotoPropertiesUpdateHandler exif, File filePath) { + private StringBuilder debugExif(StringBuilder sb, String context, PhotoPropertiesUpdateHandler exif, IFile filePath) { if (sb != null) { sb.append("\n\t").append(context).append("\t: "); @@ -62,7 +64,13 @@ public PhotoPropertiesBulkUpdateService(TransactionLoggerBase transactionLogger) this.transactionLogger = transactionLogger; } + + @Deprecated public PhotoPropertiesUpdateHandler saveLatLon(File filePath, Double latitude, Double longitude) { + return saveLatLon(FileFacade.convert(filePath), latitude, longitude); + } + + public PhotoPropertiesUpdateHandler saveLatLon(IFile filePath, Double latitude, Double longitude) { IPhotoProperties changedData = new PhotoPropertiesDTO().setLatitudeLongitude(latitude, longitude); PhotoPropertiesDiffCopy metaDiffCopy = new PhotoPropertiesDiffCopy(true, true) .setDiff(changedData, PhotoPropertiesFormatter.FieldID.latitude_longitude); @@ -71,14 +79,22 @@ public PhotoPropertiesUpdateHandler saveLatLon(File filePath, Double latitude, D return exif; } - /** writes either (changes + _affectedFields) or metaDiffCopy to jpg/xmp-filePath. - * Returns new values or null if no change. */ + @Deprecated public PhotoPropertiesUpdateHandler applyChanges(File inFilePath, String outFilePath, long id, boolean deleteOriginalWhenFinished, PhotoPropertiesDiffCopy metaDiffCopy) { + return applyChanges(FileFacade.convert(inFilePath), outFilePath, id, deleteOriginalWhenFinished, metaDiffCopy); + } + + /** + * writes either (changes + _affectedFields) or metaDiffCopy to jpg/xmp-filePath. + * Returns new values or null if no change. + */ + public PhotoPropertiesUpdateHandler applyChanges(IFile inFilePath, String outFilePath, + long id, boolean deleteOriginalWhenFinished, PhotoPropertiesDiffCopy metaDiffCopy) { StringBuilder sb = (LibGlobal.debugEnabled) ? createDebugStringBuilder(inFilePath) : null; - File outFile = (outFilePath != null) ? new File(outFilePath) : inFilePath; + IFile outFile = (outFilePath != null) ? FileFacade.convert(new File(outFilePath)) : inFilePath; if ((inFilePath != null) && outFile.getParentFile().canWrite()) { PhotoPropertiesUpdateHandler exifHandler = null; try { @@ -89,7 +105,7 @@ public PhotoPropertiesUpdateHandler applyChanges(File inFilePath, String outFile boolean sameFile = (outFile.equals(inFilePath)); - File newOutFile = handleVisibility(metaDiffCopy.getVisibility(), outFile, exifHandler); + IFile newOutFile = handleVisibility(metaDiffCopy.getVisibility(), outFile, exifHandler); if (newOutFile != null) { outFile = newOutFile; outFilePath = outFile.getAbsolutePath(); @@ -132,7 +148,7 @@ public PhotoPropertiesUpdateHandler applyChanges(File inFilePath, String outFile } if (!sameFile && deleteOriginalWhenFinished) { - File delete = FileProcessor.getSidecar(inFilePath, false); + IFile delete = FileProcessor.getSidecar(inFilePath, false); deleteFile(delete); delete = FileProcessor.getSidecar(inFilePath, true); @@ -171,7 +187,12 @@ public PhotoPropertiesUpdateHandler applyChanges(File inFilePath, String outFile } } + @Deprecated protected void deleteFile(File delete) { + deleteFile(FileFacade.convert(delete)); + } + + protected void deleteFile(IFile delete) { if ((delete != null) && delete.exists()) { delete.delete(); if (LibGlobal.debugEnabledJpg) { @@ -180,8 +201,12 @@ protected void deleteFile(File delete) { } } - /** return modified out file or null if filename must not change due to visibility rule */ protected File handleVisibility(VISIBILITY newVisibility, File outFile, PhotoPropertiesUpdateHandler exif) { + return handleVisibility(newVisibility, FileFacade.convert(outFile), exif).getFile(); + + } + /** return modified out file or null if filename must not change due to visibility rule */ + protected IFile handleVisibility(VISIBILITY newVisibility, IFile outFile, PhotoPropertiesUpdateHandler exif) { if (LibGlobal.renamePrivateJpg) { final String oldAbsoluteOutPath = (outFile == null) ? null : outFile.getAbsolutePath(); String newAbsoluteOutPath = PhotoPropertiesUtil.getModifiedPath(oldAbsoluteOutPath, newVisibility); @@ -193,18 +218,22 @@ protected File handleVisibility(VISIBILITY newVisibility, File outFile, PhotoPro transactionLogger.addChangesCopyMove(true, newAbsoluteOutPath, "handleVisibility"); } exif.setAbsoluteJpgOutPath(newAbsoluteOutPath); - return new File(newAbsoluteOutPath); + return FileFacade.convert(new File(newAbsoluteOutPath)); } } return null; } - /** todo overwrite in android class to implement update media db */ + @Deprecated protected long updateMediaDB(long id, String oldJpgAbsolutePath, File newJpgFile) { + return updateMediaDB(id, oldJpgAbsolutePath, FileFacade.convert(newJpgFile)); + } + /** todo overwrite in android class to implement update media db */ + protected long updateMediaDB(long id, String oldJpgAbsolutePath, IFile newJpgFile) { return id; } - private StringBuilder createDebugStringBuilder(File filePath) { + private StringBuilder createDebugStringBuilder(IFile filePath) { if(filePath != null) { return new StringBuilder("Set Exif to file='").append(filePath.getAbsolutePath()).append("'\n\t"); } diff --git a/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesUpdateHandler.java b/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesUpdateHandler.java index d17bd4d1..cef7c191 100644 --- a/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesUpdateHandler.java +++ b/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesUpdateHandler.java @@ -28,8 +28,10 @@ import de.k3b.LibGlobal; import de.k3b.io.FileCommands; +import de.k3b.io.FileFacade; import de.k3b.io.FileProcessor; import de.k3b.io.FileUtils; +import de.k3b.io.IFile; /** * Represents content of exactly one jpg-exif-file with corresponding xmp-file that can be modified @@ -124,7 +126,7 @@ protected static PhotoPropertiesUpdateHandler create( // xmp should have the same data as exif/iptc PhotoPropertiesUtil.copyNonEmpty(xmp, jpg); if ((absoluteJpgInPath != null) && (xmp.getDateTimeTaken() == null)) { - File in = new File(absoluteJpgInPath); + IFile in = FileFacade.convert(new File(absoluteJpgInPath)); if (in.exists() && in.isFile()) { long lastModified = in.lastModified(); if (lastModified != 0) { @@ -239,7 +241,7 @@ private int copyReplaceIfExist( String absoluteJpgInPath, String outJpgFullPath, boolean longFormat, String dbg_context) throws IOException { int changedFiles = 0; - File xmpInFile = FileCommands.getExistingSidecarOrNull(absoluteJpgInPath, longFormat); + IFile xmpInFile = FileCommands.getExistingSidecarOrNull(absoluteJpgInPath, longFormat); if (xmpInFile != null) { FileUtils.copyReplace( xmpInFile, FileCommands.getSidecar(outJpgFullPath, longFormat), @@ -253,7 +255,7 @@ private int saveXmp( PhotoPropertiesXmpSegment xmp, String outFullJpgPath, boolean isLongFileName, String dbg_context) throws IOException { - File xmpOutFile = FileCommands.getSidecar(outFullJpgPath, isLongFileName); + IFile xmpOutFile = FileCommands.getSidecar(outFullJpgPath, isLongFileName); xmp.save(xmpOutFile, LibGlobal.debugEnabledJpgMetaIo, dbg_context); return 1; } @@ -266,7 +268,7 @@ private int transferExif(String dbg_context) throws IOException { if (exif != null) { if (!isSameFile) { - exif.saveAttributes(new File(inJpgFullPath), new File(outJpgFullPath), + exif.saveAttributes(FileFacade.convert(new File(inJpgFullPath)), FileFacade.convert(new File(outJpgFullPath)), this.deleteOriginalAfterFinish); } else { exif.saveAttributes(); diff --git a/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesXmpSegment.java b/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesXmpSegment.java index 925c76c5..958f1457 100644 --- a/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesXmpSegment.java +++ b/fotolib2/src/main/java/de/k3b/media/PhotoPropertiesXmpSegment.java @@ -35,9 +35,10 @@ import de.k3b.LibGlobal; import de.k3b.io.DateUtil; import de.k3b.io.FileCommands; +import de.k3b.io.FileFacade; import de.k3b.io.GeoUtil; +import de.k3b.io.IFile; import de.k3b.io.VISIBILITY; - import de.k3b.media.MediaFormatter.FieldID; /** * {@link XmpSegment} that implements {@link IPhotoProperties} to read/write xmp. @@ -198,13 +199,19 @@ public XmpSegment setXmpMeta(XMPMeta xmpMeta, String dbg_context) { return this; } + @Deprecated @Override public XmpSegment save(File file, boolean humanReadable, String dbg_context) throws FileNotFoundException { + return save(FileFacade.convert(file), humanReadable, dbg_context); + } + + @Override + public XmpSegment save(IFile file, boolean humanReadable, String dbg_context) throws FileNotFoundException { fixAttributes(file); return super.save(file, humanReadable, dbg_context); } - private void fixAttributes(File file) { + private void fixAttributes(IFile file) { if (getPropertyAsString(" fixAttributes OriginalFileName", PhotoPropertiesXmpFieldDefinition.OriginalFileName) == null) { setProperty(file.getName(), PhotoPropertiesXmpFieldDefinition.OriginalFileName); } diff --git a/fotolib2/src/main/java/de/k3b/media/XmpSegment.java b/fotolib2/src/main/java/de/k3b/media/XmpSegment.java index 7f1f7876..f717a8ee 100644 --- a/fotolib2/src/main/java/de/k3b/media/XmpSegment.java +++ b/fotolib2/src/main/java/de/k3b/media/XmpSegment.java @@ -34,9 +34,7 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -45,7 +43,9 @@ import java.util.List; import de.k3b.LibGlobal; +import de.k3b.io.FileFacade; import de.k3b.io.FileUtils; +import de.k3b.io.IFile; import de.k3b.tagDB.TagConverter; /** @@ -60,6 +60,7 @@ public class XmpSegment { // public: can be changed in settings dialog public static boolean DEBUG = false; + private XMPMeta xmpMeta = null; private static XMPSchemaRegistry registry = XMPMetaFactory.getSchemaRegistry(); @@ -225,10 +226,15 @@ public XmpSegment load(InputStream is, String dbg_context) { return this; } + @Deprecated public XmpSegment load(File file, String dbg_context) throws FileNotFoundException { - FileInputStream stream = null; + return load(FileFacade.convert(file), dbg_context); + } + + public XmpSegment load(IFile file, String dbg_context) throws FileNotFoundException { + InputStream stream = null; try { - stream = new FileInputStream(file); + stream = file.openInputStream(); setXmpMeta(XMPMetaFactory.parse(stream), dbg_context + " file:" + file); } catch (XMPException e) { onError("->XmpSegment.load " + file, e); @@ -236,7 +242,7 @@ public XmpSegment load(File file, String dbg_context) throws FileNotFoundExcepti // workaround: my android-4.2 tahblet cannot re-read it-s xmp without trailing "\n" if ((file != null) && file.exists()) { try { - setXmpMeta(XMPMetaFactory.parse(FileUtils.streamFromStringContent(FileUtils.readFile(file) + "\n")), XmpSegment.dbg_context); + setXmpMeta(XMPMetaFactory.parse(FileUtils.streamFromStringContent(FileUtils.readFile(file.openInputStream()) + "\n")), XmpSegment.dbg_context); } catch (IOException e1) { onError("->XmpSegment.load-via-string " + file, e); } catch (XMPException e1) { @@ -250,17 +256,21 @@ public XmpSegment load(File file, String dbg_context) throws FileNotFoundExcepti return this; } + @Deprecated public XmpSegment save(File file, boolean humanReadable, String dbg_context) throws FileNotFoundException { - FileOutputStream stream = null; + return save(FileFacade.convert(file), humanReadable, dbg_context); + } + + public XmpSegment save(IFile file, boolean humanReadable, String dbg_context) throws FileNotFoundException { + OutputStream stream = null; try { - stream = new FileOutputStream(file); + stream = file.openOutputStream(); save(stream, humanReadable, dbg_context + file); } finally { FileUtils.close(stream, file); setFilelastModified(file); } return this; - } public XmpSegment save(OutputStream os, boolean humanReadable, String dbg_context) { @@ -331,7 +341,12 @@ private void appendXmpPropertyInfo(final StringBuilder result, String printPrefi } /** when xmp sidecar file was last modified or 0 */ + @Deprecated public void setFilelastModified(File file) { + setFilelastModified(FileFacade.convert(file)); + } + + public void setFilelastModified(IFile file) { if (file != null) this.filelastModified = file.lastModified() / 1000; // File/Date has millisecs } diff --git a/fotolib2/src/test/java/de/k3b/TestUtil.java b/fotolib2/src/test/java/de/k3b/TestUtil.java index fc8f34f9..e46b5092 100644 --- a/fotolib2/src/test/java/de/k3b/TestUtil.java +++ b/fotolib2/src/test/java/de/k3b/TestUtil.java @@ -28,10 +28,12 @@ import de.k3b.csv2db.csv.CsvReader; import de.k3b.io.DateUtil; +import de.k3b.io.FileFacade; import de.k3b.io.FileUtils; +import de.k3b.io.IFile; import de.k3b.io.VISIBILITY; -import de.k3b.media.PhotoPropertiesImageReaderIntegrationTests; import de.k3b.media.PhotoPropertiesDTO; +import de.k3b.media.PhotoPropertiesImageReaderIntegrationTests; import de.k3b.tagDB.TagConverter; public class TestUtil { @@ -83,6 +85,10 @@ public static InputStream getResourceInputStream(String fileName) { } public static File saveTestResourceAs(String resourceName, File destination) throws IOException { + return saveTestResourceAs(resourceName, FileFacade.convert(destination)).getFile(); + } + + public static IFile saveTestResourceAs(String resourceName, IFile destination) throws IOException { InputStream sourceStream = getResourceInputStream(resourceName); FileUtils.copyReplace(sourceStream, destination); diff --git a/fotolib2/src/test/java/de/k3b/io/FileCommandAutoIntegrationTests.java b/fotolib2/src/test/java/de/k3b/io/FileCommandAutoIntegrationTests.java index fff3b6b3..f3481a0a 100644 --- a/fotolib2/src/test/java/de/k3b/io/FileCommandAutoIntegrationTests.java +++ b/fotolib2/src/test/java/de/k3b/io/FileCommandAutoIntegrationTests.java @@ -19,30 +19,6 @@ package de.k3b.io; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.util.Date; - -import de.k3b.LibGlobal; -import de.k3b.TestUtil; -import de.k3b.io.collections.SelectedFiles; -import de.k3b.media.ExifInterface; -import de.k3b.media.ExifInterfaceEx; -import de.k3b.media.IPhotoProperties; -import de.k3b.media.MediaFormatter.FieldID; -import de.k3b.media.PhotoPropertiesBulkUpdateService; -import de.k3b.media.PhotoPropertiesDTO; -import de.k3b.media.PhotoPropertiesDiffCopy; -import de.k3b.media.PhotoPropertiesFormatter; -import de.k3b.transactionlog.TransactionLoggerBase; - /** * check autoprocessing workflow (#93:) * @@ -50,6 +26,7 @@ */ public class FileCommandAutoIntegrationTests { + /* // Obtain a logger instance private static final Logger LOGGER = LoggerFactory.getLogger(FileCommandAutoIntegrationTests.class); public static final String TEST_CLASS_NAME = FileCommandAutoIntegrationTests.class.getSimpleName(); @@ -57,9 +34,9 @@ public class FileCommandAutoIntegrationTests { private static final String FAKE_ID = "1"; private static final String FAKE_DATE = "1223372036854775807"; - private static final File OUTDIR = new File(TestUtil.OUTDIR_ROOT, TEST_CLASS_NAME + "/out").getAbsoluteFile(); - private static final File INDIR = new File(TestUtil.OUTDIR_ROOT, TEST_CLASS_NAME + "/in").getAbsoluteFile(); - private static final File INJPG = new File(INDIR, "myTestSource.jpg").getAbsoluteFile(); + private static final IFile OUTDIR = FileFacade.convert(new File(TestUtil.OUTDIR_ROOT, TEST_CLASS_NAME + "/out").getAbsoluteFile()); + private static final IFile INDIR = FileFacade.convert(new File(TestUtil.OUTDIR_ROOT, TEST_CLASS_NAME + "/in").getAbsoluteFile()); + private static final IFile INJPG = FileFacade.convert(new File(INDIR.getFile(), "myTestSource.jpg").getAbsoluteFile()); public static final SelectedFiles FAKE_SELECTED_FILES = SelectedFiles.create(INJPG.getAbsolutePath(), FAKE_ID, FAKE_DATE); @BeforeClass @@ -87,7 +64,7 @@ public void setUp() { public void shouldApplyExifChange() throws IOException { String outFileBaseName = "shouldApplyExifChange"; FileCommands sut = createFileCommands(outFileBaseName); - final File testJpg = new File(OUTDIR, outFileBaseName + ".jpg"); + final File testJpg = new File(OUTDIR.getFile(), outFileBaseName + ".jpg"); TestUtil.saveTestResourceAs(TestUtil.TEST_FILE_JPG_WITH_NO_EXIF, testJpg); PhotoPropertiesDiffCopy addExif = new PhotoPropertiesDiffCopy(new PhotoPropertiesDTO().setTitle("title added by " + TEST_CLASS_NAME), true); @@ -102,7 +79,7 @@ public void shouldApplyExifChange() throws IOException { public void shouldCopy() { String outFileBaseName = "shouldCopy"; FileCommands sut = createFileCommands(outFileBaseName); - RuleFileNameProcessor rename = new RuleFileNameProcessor(null, outFileBaseName, null, OUTDIR); + RuleFileNameProcessor rename = new RuleFileNameProcessor(null, outFileBaseName, null, OUTDIR.getFile()); sut.moveOrCopyFilesTo(false, null, FAKE_SELECTED_FILES, rename, OUTDIR, null); assertFilesExist(true, outFileBaseName); } @@ -113,7 +90,7 @@ public void shouldCopyExif() { PhotoPropertiesDiffCopy addExif = new PhotoPropertiesDiffCopy(new PhotoPropertiesDTO().setTitle("title added by " + TEST_CLASS_NAME), true); FileCommands sut = createFileCommands(outFileBaseName); - RuleFileNameProcessor rename = new RuleFileNameProcessor(null, outFileBaseName, null, OUTDIR); + RuleFileNameProcessor rename = new RuleFileNameProcessor(null, outFileBaseName, null, OUTDIR.getFile()); sut.moveOrCopyFilesTo(false, addExif, FAKE_SELECTED_FILES, rename, OUTDIR, null); assertFilesExist(true, outFileBaseName); } @@ -122,7 +99,7 @@ public void shouldCopyExif() { public void shouldCopyNoRename() { String outFileBaseName = "shouldCopyNoRename"; FileCommands sut = createFileCommands(outFileBaseName); - RuleFileNameProcessor rename = new RuleFileNameProcessor(null, "Test", null, OUTDIR); + RuleFileNameProcessor rename = new RuleFileNameProcessor(null, "Test", null, OUTDIR.getFile()); sut.moveOrCopyFilesTo(false, null, FAKE_SELECTED_FILES, rename, OUTDIR, null); assertFilesExist(true, "myTestSource"); // has still old name. Not Renamed } @@ -131,7 +108,7 @@ public void shouldCopyNoRename() { public void autoShouldAddTagSameFileNoRenameRule() throws IOException { final String outFileBaseName = "autoShouldAddTagSameFileNoRenameRule"; final String tagAdded = outFileBaseName + "_" + (DateUtil.toIsoDateTimeString(new Date()).replace(":","_") ); - final File inFile = new File(OUTDIR, outFileBaseName + ".jpg"); + final File inFile = new File(OUTDIR.getFile(), outFileBaseName + ".jpg"); TestUtil.saveTestResourceAs(TestUtil.TEST_FILE_JPG_WITH_EXIF, inFile); @@ -140,7 +117,7 @@ public void autoShouldAddTagSameFileNoRenameRule() throws IOException { final IPhotoProperties exifChanges = new PhotoPropertiesDTO(); exifChanges.setTags(ListUtils.fromString(tagAdded)); - PhotoAutoprocessingDto autoProccessData = new PhotoAutoprocessingDto(OUTDIR, new Properties()) + PhotoAutoprocessingDto autoProccessData = new PhotoAutoprocessingDto(OUTDIR.getFile(), new Properties()) .setMediaDefaults(exifChanges); int changes = sut.moveOrCopyFilesTo(true, selectedFiles, OUTDIR, @@ -317,4 +294,6 @@ private void assertFileExist(boolean expected, String outFileName) { File f = new File(OUTDIR, outFileName); Assert.assertEquals(f.toString(), expected, f.exists()); } + + */ } diff --git a/fotolib2/src/test/java/de/k3b/io/FileNameProcessorTests.java b/fotolib2/src/test/java/de/k3b/io/FileNameProcessorTests.java index cf413d9d..8ec50c58 100644 --- a/fotolib2/src/test/java/de/k3b/io/FileNameProcessorTests.java +++ b/fotolib2/src/test/java/de/k3b/io/FileNameProcessorTests.java @@ -160,9 +160,11 @@ public void shouldFixRuleOnFileChange() { private static void registerFakeFiles(RuleFileNameProcessor sut, String... filenames) { if (filenames.length == 0) { doReturn(false).when(sut).osFileExists(any(File.class)); + doReturn(false).when(sut).osFileExists(any(IFile.class)); } else { for (String filename : filenames) { doReturn(true).when(sut).osFileExists(new File(X_FAKE_OUTPUT_DIR, filename)); + doReturn(true).when(sut).osFileExists(new FileFacade(new File(X_FAKE_OUTPUT_DIR, filename))); } } }