Java tutorial
/******************************************************************************* * PGPTool is a desktop application for pgp encryption/decryption * Copyright (C) 2017 Sergey Karpushin * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> *******************************************************************************/ package org.pgptool.gui.ui.decryptone; import static org.pgptool.gui.app.Messages.text; import java.awt.Desktop; import java.awt.event.ActionEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import javax.swing.Action; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileNameExtensionFilter; import org.apache.commons.io.FilenameUtils; import org.apache.log4j.Logger; import org.pgptool.gui.app.EntryPoint; import org.pgptool.gui.app.Message; import org.pgptool.gui.app.MessageSeverity; import org.pgptool.gui.bkgoperation.UserRequestedCancellationException; import org.pgptool.gui.configpairs.api.ConfigPairs; import org.pgptool.gui.decryptedlist.api.DecryptedFile; import org.pgptool.gui.decryptedlist.api.MonitoringDecryptedFilesService; import org.pgptool.gui.encryption.api.EncryptionService; import org.pgptool.gui.encryption.api.KeyRingService; import org.pgptool.gui.encryptionparams.api.EncryptionParamsStorage; import org.pgptool.gui.filecomparison.ChecksumCalcOutputStreamSupervisor; import org.pgptool.gui.filecomparison.ChecksumCalcOutputStreamSupervisorImpl; import org.pgptool.gui.filecomparison.ChecksumCalculationTask; import org.pgptool.gui.filecomparison.Fingerprint; import org.pgptool.gui.filecomparison.MessageDigestFactory; import org.pgptool.gui.tempfolderfordecrypted.api.DecryptedTempFolder; import org.pgptool.gui.tools.FileUtilsEx; import org.pgptool.gui.ui.decryptonedialog.KeyAndPasswordCallback; import org.pgptool.gui.ui.encryptone.EncryptOnePm; import org.pgptool.gui.ui.encryptone.EncryptionDialogParameters; import org.pgptool.gui.ui.getkeypassword.PasswordDeterminedForKey; import org.pgptool.gui.ui.tools.ProgressHandlerPmMixinImpl; import org.pgptool.gui.ui.tools.UiUtils; import org.pgptool.gui.ui.tools.browsefs.ExistingFileChooserDialog; import org.pgptool.gui.ui.tools.browsefs.SaveFileChooserDialog; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.summerb.approaches.validation.ValidationError; import org.summerb.approaches.validation.ValidationErrorsUtils; import org.summerb.approaches.validation.errors.FieldRequiredValidationError; import com.google.common.base.Preconditions; import ru.skarpushin.swingpm.base.PresentationModelBase; import ru.skarpushin.swingpm.collections.ListEx; import ru.skarpushin.swingpm.collections.ListExImpl; import ru.skarpushin.swingpm.modelprops.ModelProperty; import ru.skarpushin.swingpm.modelprops.ModelPropertyAccessor; import ru.skarpushin.swingpm.tools.actions.LocalizedAction; import ru.skarpushin.swingpm.valueadapters.ValueAdapterHolderImpl; public class DecryptOnePm extends PresentationModelBase implements InitializingBean { private static final String FN_SOURCE_FILE = "sourceFile"; private static final String FN_TARGET_FILE = "targetFile"; private static Logger log = Logger.getLogger(DecryptOnePm.class); private static final String SOURCE_FOLDER = "DecryptOnePm.SOURCE_FOLDER"; public static final String CONFIG_PAIR_BASE = "Decrypt:"; private static final String[] EXTENSIONS = new String[] { "gpg", "pgp", "asc" }; @Autowired private ConfigPairs appProps; @Autowired private ConfigPairs decryptionParams; @Autowired private ExecutorService executorService; @Autowired private EncryptionParamsStorage encryptionParamsStorage; @Autowired private DecryptedTempFolder decryptedTempFolder; @Autowired // @Resource(name = "keyRingService") private KeyRingService keyRingService; @Autowired // @Resource(name = "encryptionService") private EncryptionService encryptionService; @Autowired private MonitoringDecryptedFilesService monitoringDecryptedFilesService; @Autowired private MessageDigestFactory messageDigestFactory; private DecryptOneHost host; private ModelProperty<String> sourceFile; private ModelProperty<Boolean> isUseSameFolder; private ModelProperty<Boolean> isUseTempFolder; private ModelProperty<Boolean> isUseBrowseFolder; private ModelProperty<String> targetFile; private ModelProperty<Boolean> targetFileEnabled; private ModelProperty<Boolean> isDeleteSourceAfter; private ModelProperty<Boolean> isOpenTargetFolderAfter; private ModelProperty<Boolean> isOpenAssociatedApplication; private ListEx<ValidationError> validationErrors = new ListExImpl<ValidationError>(); private ExistingFileChooserDialog sourceFileChooser; private SaveFileChooserDialog targetFileChooser; private Set<String> sourceFileRecipientsKeysIds; private PasswordDeterminedForKey keyAndPassword; private String anticipatedTargetFileName; private DecryptionDialogParameters decryptionDialogParameters; private ModelProperty<Boolean> isProgressVisible; private ModelProperty<Integer> progressValue; private ModelProperty<String> progressNote; private ModelProperty<Boolean> isDisableControls; private ProgressHandlerPmMixinImpl progressHandler; private Thread operationThread; @Override public void afterPropertiesSet() throws Exception { } public boolean init(DecryptOneHost host, String optionalSource) { Preconditions.checkArgument(host != null); this.host = host; if (!doWeHaveKeysToDecryptWith()) { return false; } initModelProperties(); if (optionalSource == null) { if (getSourceFileChooser().askUserForFile() == null) { return false; } } else { sourceFile.setValueByOwner(optionalSource); } return true; } private void initModelProperties() { sourceFile = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(), FN_SOURCE_FILE, validationErrors); sourceFile.getModelPropertyAccessor().addPropertyChangeListener(onSourceFileModified); isUseTempFolder = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(true), "saveToTempFolder"); isUseSameFolder = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(false), "saveToSameFolder"); isUseBrowseFolder = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(false), "saveToBrowseFolder"); targetFile = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(), FN_TARGET_FILE, validationErrors); targetFile.getModelPropertyAccessor().addPropertyChangeListener(onTargetFileModified); targetFileEnabled = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(), "targetFileEnabled"); isUseBrowseFolder.getModelPropertyAccessor().addPropertyChangeListener(onUseBrowseFolderChanged); onUseBrowseFolderChanged.propertyChange(null); isDeleteSourceAfter = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(false), "deleteSourceAfter"); isOpenTargetFolderAfter = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(false), "openTargetFolder"); isOpenAssociatedApplication = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(false), "openAssociatedApplication"); isDisableControls = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(false), "isDisableControls"); isProgressVisible = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(false), "isProgressVisible"); progressValue = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(0), "progressValue"); progressNote = new ModelProperty<>(this, new ValueAdapterHolderImpl<>(""), "progressNote"); progressHandler = new ProgressHandlerPmMixinImpl(isProgressVisible, progressValue, progressNote); } public SaveFileChooserDialog getTargetFileChooser() { if (targetFileChooser == null) { targetFileChooser = new SaveFileChooserDialog(findRegisteredWindowIfAny(), "action.chooseTargetFile", "action.choose", appProps, "DecryptionTargetChooser") { @Override protected String onDialogClosed(String filePathName, JFileChooser ofd) { String ret = super.onDialogClosed(filePathName, ofd); if (ret != null) { targetFile.setValueByOwner(ret); } return ret; } @Override protected void suggestTarget(JFileChooser ofd) { String sourceFileStr = sourceFile.getValue(); if (StringUtils.hasText(targetFile.getValue())) { // Case 1: Based on current target use(ofd, targetFile.getValue()); } else if (decryptionDialogParameters != null && decryptionDialogParameters.getTargetFile() != null) { if (decryptionDialogParameters.getSourceFile().equals(sourceFileStr)) { // exact match use(ofd, decryptionDialogParameters.getTargetFile()); } else { // case when suggested parameters are provided for // neighbor use(ofd, madeUpTargetFileName(FilenameUtils .getFullPathNoEndSeparator(decryptionDialogParameters.getTargetFile()))); } } else if (StringUtils.hasText(sourceFileStr) && new File(sourceFileStr).exists()) { use(ofd, madeUpTargetFileName(FilenameUtils.getFullPathNoEndSeparator(sourceFileStr))); } } private void use(JFileChooser ofd, String filePathName) { ofd.setCurrentDirectory(new File(FilenameUtils.getFullPathNoEndSeparator(filePathName))); ofd.setSelectedFile(new File(filePathName)); } }; } return targetFileChooser; } private boolean doWeHaveKeysToDecryptWith() { if (!keyRingService.readKeys().isEmpty()) { return true; } UiUtils.messageBox(text("phrase.noKeysForDecryption"), text("term.attention"), MessageSeverity.WARNING); host.getActionToOpenCertificatesList().actionPerformed(null); if (keyRingService.readKeys().isEmpty()) { return false; } return true; } public ExistingFileChooserDialog getSourceFileChooser() { if (sourceFileChooser == null) { sourceFileChooser = new ExistingFileChooserDialog(findRegisteredWindowIfAny(), appProps, SOURCE_FOLDER) { @Override protected void doFileChooserPostConstruct(JFileChooser ofd) { super.doFileChooserPostConstruct(ofd); ofd.setAcceptAllFileFilterUsed(false); ofd.addChoosableFileFilter( new FileNameExtensionFilter("Encrypted files (.gpg, .pgp, .asc)", EXTENSIONS)); ofd.addChoosableFileFilter(ofd.getAcceptAllFileFilter()); ofd.setFileFilter(ofd.getChoosableFileFilters()[0]); ofd.setDialogTitle(text("phrase.selectFileToDecrypt")); } @Override protected String handleFileWasChosen(String filePathName) { if (filePathName == null) { return null; } sourceFile.setValueByOwner(filePathName); return filePathName; } }; } return sourceFileChooser; } private PropertyChangeListener onTargetFileModified = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { clearValidationErrorsFromTargetFile(); validateTargetFile(); } }; private boolean validateTargetFile() { if (!isUseBrowseFolder.getValue()) { return true; } if (!StringUtils.hasText(targetFile.getValue())) { validationErrors.add(new FieldRequiredValidationError(FN_TARGET_FILE)); return false; } return true; } private void clearValidationErrorsFromTargetFile() { validationErrors.removeAll(ValidationErrorsUtils.findErrorsForField(FN_TARGET_FILE, validationErrors)); } @SuppressWarnings("deprecation") private PropertyChangeListener onSourceFileModified = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { log.debug("Source changed to : " + sourceFile.getValue()); validationErrors.removeAll(ValidationErrorsUtils.findErrorsForField(FN_SOURCE_FILE, validationErrors)); try { String sourceFileStr = sourceFile.getValue(); if (!StringUtils.hasText(sourceFileStr)) { validationErrors.add(new FieldRequiredValidationError(FN_SOURCE_FILE)); return; } if (!new File(sourceFileStr).exists()) { validationErrors.add(new ValidationError("error.thisFileDoesntExist", FN_SOURCE_FILE)); return; } // Determine key and password here sourceFileRecipientsKeysIds = encryptionService.findKeyIdsForDecryption(sourceFileStr); if (keyAndPassword != null && sourceFileRecipientsKeysIds.contains(keyAndPassword.getDecryptionKeyId())) { keyAndPasswordCallback.onKeyPasswordResult(keyAndPassword); } else { Message purpose = new Message("phrase.needKeyToDecryptFile", new Object[] { FilenameUtils.getName(sourceFileStr) }); // Detour host.askUserForKeyAndPassword(sourceFileRecipientsKeysIds, purpose, keyAndPasswordCallback); // NOTE: That might lead to immediate sync call to // keyAndPasswordCallback if password was cached. If user // needs to be requested then new window will appear and // callback will be called later upon user input event } } catch (Throwable t) { log.error("Failed to find decryption keys", t); validationErrors.add( new ValidationError("error.failedToDetermineDecryptionMetodsForGivenFile", FN_SOURCE_FILE)); } finally { updatePrimaryOperationAvailability(); } } private KeyAndPasswordCallback keyAndPasswordCallback = (PasswordDeterminedForKey keyAndPassword) -> { try { DecryptOnePm.this.keyAndPassword = keyAndPassword; if (keyAndPassword == null) { validationErrors.add(new ValidationError("error.noMatchingKeysRegistered", FN_SOURCE_FILE)); return; } String sourceFileStr = sourceFile.getValue(); // Get target file name ("pre-decrypt") String targetFileName = encryptionService.getNameOfFileEncrypted(sourceFileStr, keyAndPassword); anticipatedTargetFileName = patchTargetFilenameIfNeeded(sourceFileStr, targetFileName); // Continue with source file change handling decryptionDialogParameters = findParamsBasedOnSourceFile(sourceFile.getValue()); if (decryptionDialogParameters != null) { useSugestedParameters(decryptionDialogParameters); } } catch (Throwable t) { log.error("Failed to find decryption keys", t); validationErrors.add( new ValidationError("error.failedToDetermineDecryptionMetodsForGivenFile", FN_SOURCE_FILE)); } finally { updatePrimaryOperationAvailability(); } }; private String patchTargetFilenameIfNeeded(String sourceFileStr, String targetFilename) { if (StringUtils.hasText(targetFilename)) { if (targetFilename.contains("/")) { targetFilename = targetFilename.substring(targetFilename.lastIndexOf("/") + 1); } else if (targetFilename.contains("\\")) { targetFilename = targetFilename.substring(targetFilename.lastIndexOf("\\") + 1); } } if (!StringUtils.hasText(targetFilename)) { targetFilename = FilenameUtils.getBaseName(sourceFileStr); log.warn("Wasn't able to find initial file name from " + sourceFileStr + ". Will use this name: " + targetFilename); } return targetFilename; } protected DecryptionDialogParameters findParamsBasedOnSourceFile(String sourceFile) { DecryptionDialogParameters params = decryptionParams.find(sourceFile, null); if (params == null) { params = decryptionParams.find(FilenameUtils.getFullPathNoEndSeparator(sourceFile), null); } return params; } private void useSugestedParameters(DecryptionDialogParameters params) { if (params.isUseSameFolder() || params.isUseTempFolder()) { targetFile.setValueByOwner(""); } else { if (params.getSourceFile().equals(sourceFile.getValue())) { // if suggested parameters are exactly for this file targetFile.setValueByOwner(params.getTargetFile()); } else { // case when suggested parameters are provided for neighbor targetFile.setValueByOwner( madeUpTargetFileName(FilenameUtils.getFullPathNoEndSeparator(params.getTargetFile()))); } } // NOTE: MAGIC: We need to set it AFTER we set targetFolder. Because // then isUseBrowseFolder onChange handler will not open folder selection dialog if (params.isUseSameFolder()) { isUseTempFolder.setValueByOwner(false); isUseBrowseFolder.setValueByOwner(false); isUseSameFolder.setValueByOwner(true); } else if (params.isUseTempFolder()) { isUseBrowseFolder.setValueByOwner(false); isUseSameFolder.setValueByOwner(false); isUseTempFolder.setValueByOwner(true); } else { isUseSameFolder.setValueByOwner(false); isUseTempFolder.setValueByOwner(false); isUseBrowseFolder.setValueByOwner(true); } isDeleteSourceAfter.setValueByOwner(params.isDeleteSourceFile()); isOpenTargetFolderAfter.setValueByOwner(params.isOpenTargetFolder()); isOpenAssociatedApplication.setValueByOwner(params.isOpenAssociatedApplication()); } }; private PropertyChangeListener onUseBrowseFolderChanged = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { boolean result = isUseBrowseFolder.getValue(); actionBrowseTarget.setEnabled(result); targetFileEnabled.setValueByOwner(result); // NOTE: MAGIC: This event might be triggered when using suggested // parameters. So if value is already provided for target file then // we'll not show file chooser if (result && !StringUtils.hasText(targetFile.getValue())) { getTargetFileChooser().askUserForFile(); } if (!result) { clearValidationErrorsFromTargetFile(); } } }; protected void updatePrimaryOperationAvailability() { boolean result = true; result &= StringUtils.hasText(sourceFile.getValue()) && new File(sourceFile.getValue()).exists(); result &= keyAndPassword != null; result &= validationErrors.size() == 0; actionDoOperation.setEnabled(result); } @SuppressWarnings("serial") protected final Action actionDoOperation = new LocalizedAction("action.decrypt") { @Override public void actionPerformed(ActionEvent e) { actionDoOperation.setEnabled(false); isDisableControls.setValueByOwner(true); operationThread = new Thread(operationWorker); operationThread.start(); } }; private Runnable operationWorker = new Runnable() { @Override public void run() { String targetFileName = getEffectiveTargetFileName(); if (targetFileName == null) { actionDoOperation.setEnabled(true); isDisableControls.setValueByOwner(false); return; } String sourceFileStr = sourceFile.getValue(); Fingerprint sourceFileFingerprint = null; Fingerprint targetFileFingerprint = null; Future<Fingerprint> sourceFileFingerprintFuture = null; try { // NOTE: In parallel we'll calculate checksum of the source. I hope IO caching // layer will handle 2 reading process for same file nicely and we won't have to // report progress on source checksum separately sourceFileFingerprintFuture = executorService .submit(new ChecksumCalculationTask(sourceFileStr, messageDigestFactory.createNew())); // and here is an actual decryption process ChecksumCalcOutputStreamSupervisor outputStreamSupervisor = new ChecksumCalcOutputStreamSupervisorImpl( messageDigestFactory); FileUtilsEx.baitAndSwitch(targetFileName, x -> encryptionService.decrypt(sourceFileStr, x, keyAndPassword, progressHandler, outputStreamSupervisor)); log.debug("Decryption completed: " + targetFileName); // NOTE: We can calculate checksum for target file because we write it in full, // but input file is not really being read in full so we'll have to calculate // checksum of source file separately targetFileFingerprint = outputStreamSupervisor.getFingerprint(); // Calculate source file CRC sourceFileFingerprint = sourceFileFingerprintFuture.get(); } catch (UserRequestedCancellationException ce) { if (sourceFileFingerprintFuture != null) { sourceFileFingerprintFuture.cancel(true); } host.handleClose(); return; } catch (Throwable t) { log.error("Failed to decrypt", t); if (sourceFileFingerprintFuture != null) { sourceFileFingerprintFuture.cancel(true); } EntryPoint.reportExceptionToUser("error.failedToDecryptFile", t); actionDoOperation.setEnabled(true); isDisableControls.setValueByOwner(false); return; } // Remember parameters persistDecryptionDialogParametersForCurrentInputs(targetFileName); persistEncryptionDialogParameters(targetFileName); addToMonitoredDecrypted(sourceFileStr, targetFileName, sourceFileFingerprint, targetFileFingerprint); // Delete source if asked if (isDeleteSourceAfter.getValue()) { try { Preconditions.checkState(new File(sourceFileStr).delete(), "File.delete() returned false"); } catch (Throwable t) { EntryPoint.reportExceptionToUser("error.decryptOkButCantDeleteSource", t); } } // Open target folder boolean confirmationMessageRequired = true; if (isOpenTargetFolderAfter.getValue()) { browseForFolder(targetFileName); confirmationMessageRequired = false; } // Open target application if (isOpenAssociatedApplication.getValue()) { openAssociatedApp(targetFileName); confirmationMessageRequired = false; } if (confirmationMessageRequired) { UiUtils.messageBox(text("phrase.decryptionSuccess", targetFileName), text("term.success"), MessageSeverity.INFO); } // close window host.handleClose(); } private void addToMonitoredDecrypted(String sourceFileStr, String targetFileName, Fingerprint sourceFileFingerprint, Fingerprint targetFileFingerprint) { DecryptedFile decryptedFile = new DecryptedFile(sourceFileStr, targetFileName); decryptedFile.setEncryptedFileFingerprint(sourceFileFingerprint); decryptedFile.setDecryptedFileFingerprint(targetFileFingerprint); monitoringDecryptedFilesService.addOrUpdate(decryptedFile); } private void openAssociatedApp(String targetFileName) { try { Desktop.getDesktop().open(new File(targetFileName)); } catch (Throwable t) { EntryPoint.reportExceptionToUser("error.decryptOkButCantBrowseForFolder", t); } } private void browseForFolder(String targetFileName) { try { Desktop.getDesktop().browse(new File(targetFileName).getParentFile().toURI()); } catch (Throwable t) { EntryPoint.reportExceptionToUser("error.decryptOkButCantBrowseForFolder", t); } } private String getEffectiveTargetFileName() { if (isUseSameFolder.getValue()) { return madeUpTargetFileName(FilenameUtils.getFullPathNoEndSeparator(sourceFile.getValue())); } else if (isUseTempFolder.getValue()) { return getEffectiveFileNameForTempFolder(); } // Validation for target folder!! --- if (!validateTargetFile()) { return null; } String ret = targetFile.getValue(); File parentFolder = new File(ret).getParentFile(); Preconditions.checkState(parentFolder.exists() || parentFolder.mkdirs(), "Failed to ensure all parents directories created"); return ret; } private String getEffectiveFileNameForTempFolder() { DecryptedFile dfm = monitoringDecryptedFilesService.findByEncryptedFile(getSourceFile().getValue(), x -> x.getDecryptedFile().startsWith(decryptedTempFolder.getTempFolderBasePath())); if (dfm == null) { String ret = madeUpTargetFileName(decryptedTempFolder.getTempFolderBasePath()); return FileUtilsEx.ensureFileNameVacant(ret); } // Suggest to open instead of overwrite String msg = text("warning.fileWasAlreadyDecryptedIntoTempFolder", new Object[] { dfm.getEncryptedFile(), dfm.getDecryptedFile() }); int response = JOptionPane.showConfirmDialog(findRegisteredWindowIfAny(), UiUtils.getMultilineMessage(msg), text("term.confirmation"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (response == JOptionPane.CANCEL_OPTION) { return null; } else if (response == JOptionPane.NO_OPTION) { // overwrite return dfm.getDecryptedFile(); } else { // NOTE: That is a nasty violation of something. This method should not control // PM workflow like this. But today I don't feel myself ok, I hope you will // forgive me. Will refactor it later. if (isOpenTargetFolderAfter.getValue()) { browseForFolder(dfm.getDecryptedFile()); } else { openAssociatedApp(dfm.getDecryptedFile()); } host.handleClose(); return null; } } private void persistDecryptionDialogParametersForCurrentInputs(String targetFile) { DecryptionDialogParameters dialogParameters = buildDecryptionDialogParameters(targetFile); decryptionParams.put(dialogParameters.getSourceFile(), dialogParameters); decryptionParams.put(FilenameUtils.getFullPathNoEndSeparator(dialogParameters.getSourceFile()), dialogParameters); } /** * We use this method to store parameters that program will suggest to use when * user will desire to encrypt back file that was just decrypted * * NOTE: Slight SRP concern here. We're interfering with responsibility area of * {@link EncryptOnePm} * * @param decryptedFile * decrypted file path name */ protected void persistEncryptionDialogParameters(String decryptedFile) { EncryptionDialogParameters dialogParameters = buildEncryptionDialogParameters(decryptedFile); encryptionParamsStorage.persistDialogParametersForCurrentInputs(dialogParameters, false); } private EncryptionDialogParameters buildEncryptionDialogParameters(String decryptedFile) { EncryptionDialogParameters ret = new EncryptionDialogParameters(); ret.setPropagatedFromDecrypt(true); ret.setSourceFile(decryptedFile); ret.setUseSameFolder(false); ret.setTargetFile(sourceFile.getValue()); ret.setDeleteSourceFile(true); // questionable ret.setRecipientsKeysIds(new ArrayList<>(sourceFileRecipientsKeysIds)); return ret; } private DecryptionDialogParameters buildDecryptionDialogParameters(String targetFile) { DecryptionDialogParameters ret = new DecryptionDialogParameters(); ret.setSourceFile(sourceFile.getValue()); ret.setUseSameFolder(isUseSameFolder.getValue()); ret.setUseTempFolder(isUseTempFolder.getValue()); ret.setTargetFile(targetFile); ret.setDecryptionKeyId(keyAndPassword.getDecryptionKeyId()); ret.setDeleteSourceFile(isDeleteSourceAfter.getValue()); ret.setOpenTargetFolder(isOpenTargetFolderAfter.getValue()); ret.setOpenAssociatedApplication(isOpenAssociatedApplication.getValue()); ret.setCreatedAt(System.currentTimeMillis()); return ret; } }; private String madeUpTargetFileName(String targetBasedPath) { return targetBasedPath + File.separator + anticipatedTargetFileName; } @SuppressWarnings("serial") protected final Action actionCancel = new LocalizedAction("action.cancel") { @Override public void actionPerformed(ActionEvent e) { if (operationThread != null && operationThread.isAlive()) { operationThread.interrupt(); } else { host.handleClose(); } } }; @SuppressWarnings("serial") protected final Action actionBrowseSource = new LocalizedAction("action.browse") { @Override public void actionPerformed(ActionEvent e) { getSourceFileChooser().askUserForFile(); } }; @SuppressWarnings("serial") protected final Action actionBrowseTarget = new LocalizedAction("action.browse") { @Override public void actionPerformed(ActionEvent e) { getTargetFileChooser().askUserForFile(); } }; public ModelPropertyAccessor<Boolean> getIsDeleteSourceAfter() { return isDeleteSourceAfter.getModelPropertyAccessor(); } public ModelPropertyAccessor<Boolean> getIsOpenTargetFolderAfter() { return isOpenTargetFolderAfter.getModelPropertyAccessor(); } public ModelPropertyAccessor<Boolean> getIsUseSameFolder() { return isUseSameFolder.getModelPropertyAccessor(); } public ModelPropertyAccessor<Boolean> getIsUseTempFolder() { return isUseTempFolder.getModelPropertyAccessor(); } public ModelPropertyAccessor<Boolean> getIsUseBrowseFolder() { return isUseBrowseFolder.getModelPropertyAccessor(); } public ModelPropertyAccessor<String> getSourceFile() { return sourceFile.getModelPropertyAccessor(); } public ModelPropertyAccessor<String> getTargetFile() { return targetFile.getModelPropertyAccessor(); } public ModelPropertyAccessor<Boolean> getTargetFileEnabled() { return targetFileEnabled.getModelPropertyAccessor(); } public ModelPropertyAccessor<Boolean> getIsOpenAssociatedApplication() { return isOpenAssociatedApplication.getModelPropertyAccessor(); } public static boolean isItLooksLikeYourSourceFile(String file) { return new File(file).exists() && containsIgnoreCase(EXTENSIONS, FilenameUtils.getExtension(file).toLowerCase()); } private static boolean containsIgnoreCase(String[] arr, String subject) { for (String s : arr) { if (s.equalsIgnoreCase(subject)) { return true; } } return false; } public ModelPropertyAccessor<Boolean> getIsProgressVisible() { return isProgressVisible.getModelPropertyAccessor(); } public ModelPropertyAccessor<Integer> getProgressValue() { return progressValue.getModelPropertyAccessor(); } public ModelPropertyAccessor<String> getProgressNote() { return progressNote.getModelPropertyAccessor(); } public ModelPropertyAccessor<Boolean> getIsDisableControls() { return isDisableControls.getModelPropertyAccessor(); } }