/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package scratch; import com.intellij.openapi.util.UserDataHolder; import com.intellij.util.containers.ContainerUtil; import scratch.filesystem.FileSystem; import scratch.ide.Ide; import scratch.ide.ScratchLog; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static com.intellij.util.containers.ContainerUtil.*; import static scratch.ScratchConfig.DefaultScratchMeaning; public class MrScratchManager { private final Ide ide; private final ScratchLog log; private final FileSystem fileSystem; private ScratchConfig config; public MrScratchManager(Ide ide, FileSystem fileSystem, ScratchConfig config, ScratchLog log) { this.ide = ide; this.fileSystem = fileSystem; this.config = config; this.log = log; } public void migrate(List<String> scratchTexts) { if (!fileSystem.listScratchFiles().isEmpty()) { log.willNotMigrateBecauseTargetFolderIsNotEmpty(); return; } boolean allEmpty = !ContainerUtil.exists(scratchTexts, s -> !s.isEmpty()); if (allEmpty) { List<Scratch> scratches = Arrays.asList( Scratch.create("&scratch.txt"), Scratch.create("scratch&2.txt"), Scratch.create("scratch&3.xml"), Scratch.create("scratch&4.xml") ); for (Scratch scratch : scratches) { fileSystem.createEmptyFile(scratch.asFileName()); } updateConfig(config.with(scratches).needsMigration(false)); return; } List<Integer> indexes = new ArrayList<>(); List<Scratch> scratches = new ArrayList<>(); for (int i = 1; i <= scratchTexts.size(); i++) { String scratchName = (i == 1 ? "&scratch" : "scratch&" + i); Scratch scratch = Scratch.create(scratchName + ".txt"); boolean wasCreated = fileSystem.createFile(scratch.asFileName(), scratchTexts.get(i - 1)); if (wasCreated) { scratches.add(scratch); } else { indexes.add(i); } } if (indexes.isEmpty()) { log.migratedScratchesToFiles(); } else { log.failedToMigrateScratchesToFiles(indexes); } updateConfig(config.with(scratches).needsMigration(false)); } public void userWantsToSeeScratchesList(UserDataHolder userDataHolder) { syncScratchesWithFileSystem(); ide.displayScratchesListPopup(config.scratches, userDataHolder); } public void userWantsToOpenScratch(Scratch scratch, UserDataHolder userDataHolder) { if (fileSystem.scratchFileExists(scratch.asFileName())) { ide.openScratch(scratch, userDataHolder); } else { log.failedToOpen(scratch); } } public void userWantsToOpenDefaultScratch(UserDataHolder userDataHolder) { syncScratchesWithFileSystem(); if (config.scratches.isEmpty()) { userWantsToEnterNewScratchName(userDataHolder); return; } ide.openScratch(getDefaultScratch(), userDataHolder); } public void userWantsToChangeMeaningOfDefaultScratch(DefaultScratchMeaning value) { updateConfig(config.withDefaultScratchMeaning(value)); } public DefaultScratchMeaning defaultScratchMeaning() { return config.defaultScratchMeaning; } public void userOpenedScratch(String scratchFileName) { Scratch scratch = findByFileName(scratchFileName); if (scratch != null) { updateConfig(config.withLastOpenedScratch(scratch)); } } public void userWantsToEditScratchName(String scratchFileName) { Scratch scratch = findByFileName(scratchFileName); if (scratch != null) { userWantsToEditScratchName(scratch); } } public void userWantsToEditScratchName(Scratch scratch) { ide.showRenameDialogFor(scratch); } public Answer checkIfUserCanRename(final Scratch scratch, String fullNameWithMnemonics) { if (fullNameWithMnemonics.isEmpty()) return Answer.no("Name cannot be empty"); final Scratch renamedScratch = Scratch.create(fullNameWithMnemonics); if (scratch.asFileName().equals(renamedScratch.asFileName())) return Answer.yes(); boolean haveScratchWithSameName = exists(config.scratches, it -> !it.equals(scratch) && it.name.equals(renamedScratch.name) && it.extension.equals(renamedScratch.extension)); if (haveScratchWithSameName) return Answer.no("There is already a scratch with this name"); return fileSystem.isValidScratchName(renamedScratch.asFileName()); } public void userWantsToRename(Scratch scratch, String fullNameWithMnemonics) { if (scratch.fullNameWithMnemonics.equals(fullNameWithMnemonics)) return; Scratch renamedScratch = Scratch.create(fullNameWithMnemonics); boolean wasRenamed = fileSystem.renameFile(scratch.asFileName(), renamedScratch.asFileName()); if (wasRenamed) { updateConfig(config.replace(scratch, renamedScratch)); } else { log.failedToRename(scratch); } } public void userMovedScratch(final Scratch scratch, int shift) { updateConfig(config.move(scratch, shift)); } public void userWantsToListenToClipboard(boolean value) { updateConfig(config.listenToClipboard(value)); log.listeningToClipboard(value); } public void clipboardListenerWantsToAddTextToScratch(String clipboardText) { if (config.scratches.isEmpty()) { log.failedToOpenDefaultScratch(); } else { Scratch scratch = getDefaultScratch(); if (fileSystem.scratchFileExists(scratch.asFileName())) { ide.addTextTo(scratch, clipboardText, config.clipboardAppendType); } else { log.failedToOpenDefaultScratch(); } } } public boolean shouldListenToClipboard() { return config.listenToClipboard; } public void userWantsToEnterNewScratchName(UserDataHolder userDataHolder) { String defaultName = "scratch"; String defaultExtension = "txt"; if (isUniqueScratchName(defaultName)) { ide.openNewScratchDialog(defaultName + "." + defaultExtension, userDataHolder); return; } for (int i = 1; i < 100; i++) { if (isUniqueScratchName(defaultName + i)) { ide.openNewScratchDialog(defaultName + i + "." + defaultExtension, userDataHolder); return; } } } public Answer checkIfUserCanCreateScratchWithName(String fullNameWithMnemonics) { if (fullNameWithMnemonics.isEmpty()) return Answer.no("Name cannot be empty"); final Scratch scratch = Scratch.create(fullNameWithMnemonics); if (!isUniqueScratchName(scratch.name, scratch.extension)) return Answer.no("There is already a scratch with this name"); return fileSystem.isValidScratchName(scratch.asFileName()); } public void userWantsToAddNewScratch(String fullNameWithMnemonics, UserDataHolder userDataHolder) { Scratch scratch = Scratch.create(fullNameWithMnemonics); boolean wasCreated = fileSystem.createEmptyFile(scratch.asFileName()); if (wasCreated) { updateConfig(config.add(scratch)); ide.openScratch(scratch, userDataHolder); } else { log.failedToCreate(scratch); } } public void userAttemptedToDeleteScratch(String scratchFileName, UserDataHolder userDataHolder) { Scratch scratch = findByFileName(scratchFileName); if (scratch != null) userAttemptedToDeleteScratch(scratch, userDataHolder); } public void userAttemptedToDeleteScratch(Scratch scratch, UserDataHolder userDataHolder) { ide.showDeleteDialogFor(scratch, userDataHolder); } public void userWantsToDeleteScratch(Scratch scratch) { boolean wasRemoved = fileSystem.removeFile(scratch.asFileName()); if (wasRemoved) { updateConfig(config.without(scratch)); } else { log.failedToDelete(scratch); } } private void syncScratchesWithFileSystem() { List<String> fileNames = fileSystem.listScratchFiles(); List<Scratch> oldScratches = findAll(config.scratches, it -> fileNames.contains(it.asFileName())); List<String> newFileNames = filter(fileNames, fileName -> !exists(oldScratches, scratch -> fileName.equals(scratch.asFileName()))); List<Scratch> newScratches = map(newFileNames, Scratch::create); List<Scratch> scratches = concat(oldScratches, newScratches); if (!newScratches.isEmpty() || oldScratches.size() != config.scratches.size()) { ScratchConfig newConfig = config.with(scratches); if (!scratches.contains(config.lastOpenedScratch)) { newConfig = newConfig.withLastOpenedScratch(null); } updateConfig(newConfig); } } private Scratch getDefaultScratch() { switch (config.defaultScratchMeaning) { case TOPMOST: return config.scratches.get(0); case LAST_OPENED: return config.lastOpenedScratch != null ? config.lastOpenedScratch : config.scratches.get(0); default: throw new IllegalStateException(); } } private boolean isUniqueScratchName(final String name) { return !exists(config.scratches, it -> it.name.equals(name)); } private boolean isUniqueScratchName(final String name, final String extension) { return !exists(config.scratches, it -> it.name.equals(name) && it.extension.equals(extension)); } private void updateConfig(ScratchConfig newConfig) { if (config.equals(newConfig)) return; config = newConfig; ide.persistConfig(config); } private Scratch findByFileName(final String scratchFileName) { return ContainerUtil.find(config.scratches, it -> it.asFileName().equals(scratchFileName)); } }