mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-24 16:40:25 +00:00
Add new rename file conflict action
This commit is contained in:
parent
7f334c21e9
commit
b35b63708d
15 changed files with 98 additions and 21 deletions
|
@ -30,15 +30,22 @@ public class BrowserAlerts {
|
|||
new ButtonType(AppI18n.get("replaceAll"), ButtonBar.ButtonData.OTHER),
|
||||
FileConflictChoice.REPLACE_ALL);
|
||||
}
|
||||
map.put(new ButtonType(AppI18n.get("rename"), ButtonBar.ButtonData.OTHER), FileConflictChoice.RENAME);
|
||||
if (multiple) {
|
||||
map.put(
|
||||
new ButtonType(AppI18n.get("renameAll"), ButtonBar.ButtonData.OTHER),
|
||||
FileConflictChoice.RENAME_ALL);
|
||||
}
|
||||
return AppWindowHelper.showBlockingAlert(alert -> {
|
||||
alert.setTitle(AppI18n.get("fileConflictAlertTitle"));
|
||||
alert.setHeaderText(AppI18n.get("fileConflictAlertHeader"));
|
||||
AppWindowHelper.setContent(
|
||||
alert,
|
||||
AppI18n.get(
|
||||
multiple ? "fileConflictAlertContentMultiple" : "fileConflictAlertContent", file));
|
||||
alert.setAlertType(Alert.AlertType.CONFIRMATION);
|
||||
alert.getButtonTypes().clear();
|
||||
alert.getDialogPane().setContent(AppWindowHelper.alertContentText(AppI18n.get(
|
||||
multiple ? "fileConflictAlertContentMultiple" : "fileConflictAlertContent", file), 655));
|
||||
alert.getDialogPane().setMinWidth(705);
|
||||
alert.getDialogPane().setPrefWidth(705);
|
||||
alert.getDialogPane().setMaxWidth(705);
|
||||
map.sequencedKeySet()
|
||||
.forEach(buttonType -> alert.getButtonTypes().add(buttonType));
|
||||
})
|
||||
|
@ -97,6 +104,8 @@ public class BrowserAlerts {
|
|||
SKIP,
|
||||
SKIP_ALL,
|
||||
REPLACE,
|
||||
REPLACE_ALL
|
||||
REPLACE_ALL,
|
||||
RENAME,
|
||||
RENAME_ALL
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BrowserFileTransferOperation {
|
||||
|
||||
|
@ -63,41 +65,52 @@ public class BrowserFileTransferOperation {
|
|||
this.progress.accept(progress);
|
||||
}
|
||||
|
||||
private boolean handleChoice(FileSystem fileSystem, String target, boolean multiple) throws Exception {
|
||||
private BrowserAlerts.FileConflictChoice handleChoice(FileSystem fileSystem, String target, boolean multiple) throws Exception {
|
||||
if (lastConflictChoice == BrowserAlerts.FileConflictChoice.CANCEL) {
|
||||
return false;
|
||||
return BrowserAlerts.FileConflictChoice.CANCEL;
|
||||
}
|
||||
|
||||
if (lastConflictChoice == BrowserAlerts.FileConflictChoice.REPLACE_ALL) {
|
||||
return true;
|
||||
return BrowserAlerts.FileConflictChoice.REPLACE;
|
||||
}
|
||||
|
||||
if (lastConflictChoice == BrowserAlerts.FileConflictChoice.RENAME_ALL) {
|
||||
return BrowserAlerts.FileConflictChoice.RENAME;
|
||||
}
|
||||
|
||||
if (fileSystem.fileExists(target)) {
|
||||
if (lastConflictChoice == BrowserAlerts.FileConflictChoice.SKIP_ALL) {
|
||||
return false;
|
||||
return BrowserAlerts.FileConflictChoice.SKIP;
|
||||
}
|
||||
|
||||
var choice = BrowserAlerts.showFileConflictAlert(target, multiple);
|
||||
if (choice == BrowserAlerts.FileConflictChoice.CANCEL) {
|
||||
lastConflictChoice = BrowserAlerts.FileConflictChoice.CANCEL;
|
||||
return false;
|
||||
return BrowserAlerts.FileConflictChoice.CANCEL;
|
||||
}
|
||||
|
||||
if (choice == BrowserAlerts.FileConflictChoice.SKIP) {
|
||||
return false;
|
||||
return BrowserAlerts.FileConflictChoice.SKIP;
|
||||
}
|
||||
|
||||
if (choice == BrowserAlerts.FileConflictChoice.SKIP_ALL) {
|
||||
lastConflictChoice = BrowserAlerts.FileConflictChoice.SKIP_ALL;
|
||||
return false;
|
||||
return BrowserAlerts.FileConflictChoice.SKIP;
|
||||
}
|
||||
|
||||
if (choice == BrowserAlerts.FileConflictChoice.REPLACE_ALL) {
|
||||
lastConflictChoice = BrowserAlerts.FileConflictChoice.REPLACE_ALL;
|
||||
return true;
|
||||
return BrowserAlerts.FileConflictChoice.REPLACE;
|
||||
}
|
||||
|
||||
if (choice == BrowserAlerts.FileConflictChoice.RENAME_ALL) {
|
||||
lastConflictChoice = BrowserAlerts.FileConflictChoice.RENAME_ALL;
|
||||
return BrowserAlerts.FileConflictChoice.RENAME;
|
||||
}
|
||||
|
||||
return choice;
|
||||
}
|
||||
return true;
|
||||
return BrowserAlerts.FileConflictChoice.REPLACE;
|
||||
}
|
||||
|
||||
public void execute() throws Exception {
|
||||
|
@ -152,8 +165,15 @@ public class BrowserFileTransferOperation {
|
|||
new IllegalArgumentException("Target directory " + targetFile + " does already exist"));
|
||||
}
|
||||
|
||||
if (checkConflicts && !handleChoice(target.getFileSystem(), targetFile, files.size() > 1)) {
|
||||
return;
|
||||
if (checkConflicts) {
|
||||
var fileConflictChoice = handleChoice(target.getFileSystem(), targetFile, files.size() > 1);
|
||||
if (fileConflictChoice == BrowserAlerts.FileConflictChoice.SKIP || fileConflictChoice == BrowserAlerts.FileConflictChoice.CANCEL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileConflictChoice == BrowserAlerts.FileConflictChoice.RENAME) {
|
||||
targetFile = renameFileLoop(target.getFileSystem(), targetFile, source.getKind() == FileKind.DIRECTORY);
|
||||
}
|
||||
}
|
||||
|
||||
var doesMove = transferMode == BrowserFileTransferMode.MOVE || transferMode == BrowserFileTransferMode.NORMAL;
|
||||
|
@ -164,6 +184,33 @@ public class BrowserFileTransferOperation {
|
|||
}
|
||||
}
|
||||
|
||||
private String renameFileLoop(FileSystem fileSystem, String target, boolean dir) throws Exception {
|
||||
// Who has more than 10 copies?
|
||||
for (int i = 0; i < 10; i++) {
|
||||
target = renameFile(target);
|
||||
if ((dir && !fileSystem.directoryExists(target)) || (!dir && !fileSystem.fileExists(target))) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
private String renameFile(String target) {
|
||||
var targetFile = new FilePath(target);
|
||||
var name = targetFile.getFileName();
|
||||
var pattern = Pattern.compile("(.+?) \\((\\d+)\\)\\.(.+)");
|
||||
var matcher = pattern.matcher(name);
|
||||
if (matcher.matches()) {
|
||||
try {
|
||||
var number = Integer.parseInt(matcher.group(2));
|
||||
var newFile = targetFile.getParent().join(matcher.group(1) + " (" + (number + 1) + ")." + matcher.group(3));
|
||||
return newFile.toString();
|
||||
} catch (NumberFormatException e) {}
|
||||
}
|
||||
|
||||
return targetFile.getBaseName() + " (" + 1 + ")." + targetFile.getExtension();
|
||||
}
|
||||
|
||||
private void handleSingleAcrossFileSystems(FileEntry source) throws Exception {
|
||||
if (target.getKind() != FileKind.DIRECTORY) {
|
||||
throw new IllegalStateException("Target " + target.getPath() + " is not a directory");
|
||||
|
@ -225,10 +272,15 @@ public class BrowserFileTransferOperation {
|
|||
if (sourceFile.getKind() == FileKind.DIRECTORY) {
|
||||
target.getFileSystem().mkdirs(targetFile);
|
||||
} else if (sourceFile.getKind() == FileKind.FILE) {
|
||||
if (checkConflicts
|
||||
&& !handleChoice(
|
||||
target.getFileSystem(), targetFile, files.size() > 1 || flatFiles.size() > 1)) {
|
||||
continue;
|
||||
if (checkConflicts) {
|
||||
var fileConflictChoice = handleChoice(target.getFileSystem(), targetFile, files.size() > 1 || flatFiles.size() > 1);
|
||||
if (fileConflictChoice == BrowserAlerts.FileConflictChoice.SKIP || fileConflictChoice == BrowserAlerts.FileConflictChoice.CANCEL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileConflictChoice == BrowserAlerts.FileConflictChoice.RENAME) {
|
||||
targetFile = renameFileLoop(target.getFileSystem(), targetFile, false);
|
||||
}
|
||||
}
|
||||
|
||||
transfer(sourceFile, targetFile, transferred, totalSize, start);
|
||||
|
|
|
@ -41,8 +41,12 @@ import java.util.function.Supplier;
|
|||
public class AppWindowHelper {
|
||||
|
||||
public static Node alertContentText(String s) {
|
||||
return alertContentText(s, 450);
|
||||
}
|
||||
|
||||
public static Node alertContentText(String s, int width) {
|
||||
var text = new Text(s);
|
||||
text.setWrappingWidth(450);
|
||||
text.setWrappingWidth(width);
|
||||
AppFont.medium(text);
|
||||
var sp = new StackPane(text);
|
||||
sp.setPadding(new Insets(5));
|
||||
|
|
|
@ -530,3 +530,4 @@ dontAllowTerminalRestart=Tillad ikke genstart af terminal
|
|||
dontAllowTerminalRestartDescription=Som standard kan terminalsessioner genstartes, når de er afsluttet inde fra terminalen. For at tillade dette accepterer XPipe disse eksterne anmodninger fra terminalen om at starte sessionen igen\n\nXPipe har ingen kontrol over terminalen, og hvor dette opkald kommer fra, så ondsindede lokale programmer kan også bruge denne funktion til at starte forbindelser gennem XPipe. Ved at deaktivere denne funktion forhindres dette scenarie.
|
||||
openDocumentation=Åben dokumentation
|
||||
openDocumentationDescription=Besøg XPipes dokumentationsside for dette problem
|
||||
renameAll=Omdøb alle
|
||||
|
|
|
@ -524,3 +524,4 @@ dontAllowTerminalRestart=Terminal-Neustart nicht zulassen
|
|||
dontAllowTerminalRestartDescription=Standardmäßig können Terminalsitzungen neu gestartet werden, nachdem sie vom Terminal aus beendet wurden. Um dies zu ermöglichen, akzeptiert XPipe diese externen Anfragen vom Terminal, um die Sitzung erneut zu starten\n\nXPipe hat keine Kontrolle über das Terminal und darüber, woher dieser Aufruf kommt. Daher können böswillige lokale Anwendungen diese Funktion ebenfalls nutzen, um Verbindungen über XPipe zu starten. Die Deaktivierung dieser Funktion verhindert dieses Szenario.
|
||||
openDocumentation=Offene Dokumentation
|
||||
openDocumentationDescription=Besuche die XPipe-Dokumentationsseite zu diesem Thema
|
||||
renameAll=Alle umbenennen
|
||||
|
|
|
@ -530,3 +530,4 @@ dontAllowTerminalRestart=Don't allow terminal restart
|
|||
dontAllowTerminalRestartDescription=By default, terminal sessions can be restarted after they ended from within the terminal. To allow this, XPipe will accept these external requests from the terminal to launch the session again\n\nXPipe doesn't have any control over the terminal and where this call comes from, so malicious local applications can use this functionality as well to launch connections through XPipe. Disabling this functionality prevents this scenario.
|
||||
openDocumentation=Open documentation
|
||||
openDocumentationDescription=Visit the XPipe docs page for this issue
|
||||
renameAll=Rename all
|
||||
|
|
|
@ -511,3 +511,4 @@ dontAllowTerminalRestart=No permitir el reinicio del terminal
|
|||
dontAllowTerminalRestartDescription=Por defecto, las sesiones de terminal pueden reiniciarse una vez finalizadas desde dentro del terminal. Para permitirlo, XPipe aceptará estas peticiones externas del terminal para iniciar de nuevo la sesión\n\nXPipe no tiene ningún control sobre el terminal y de dónde procede esta llamada, por lo que las aplicaciones locales maliciosas también pueden utilizar esta funcionalidad para lanzar conexiones a través de XPipe. Deshabilitar esta funcionalidad evita este escenario.
|
||||
openDocumentation=Documentación abierta
|
||||
openDocumentationDescription=Visita la página de documentación de XPipe sobre este tema
|
||||
renameAll=Renombrar todo
|
||||
|
|
|
@ -511,3 +511,4 @@ dontAllowTerminalRestart=Ne pas autoriser le redémarrage du terminal
|
|||
dontAllowTerminalRestartDescription=Par défaut, les sessions de terminal peuvent être relancées après s'être terminées depuis le terminal. Pour permettre cela, XPipe acceptera ces demandes externes du terminal pour relancer la session\n\nXPipe n'a aucun contrôle sur le terminal et sur la provenance de cet appel, de sorte que des applications locales malveillantes peuvent également utiliser cette fonctionnalité pour lancer des connexions par l'intermédiaire de XPipe. La désactivation de cette fonctionnalité permet d'éviter ce scénario.
|
||||
openDocumentation=Documentation ouverte
|
||||
openDocumentationDescription=Visite la page de documentation de XPipe pour ce problème
|
||||
renameAll=Renommer tout
|
||||
|
|
|
@ -511,3 +511,4 @@ dontAllowTerminalRestart=Non consentire il riavvio del terminale
|
|||
dontAllowTerminalRestartDescription=Per impostazione predefinita, le sessioni del terminale possono essere riavviate dopo la loro conclusione dall'interno del terminale stesso. Per consentire ciò, XPipe accetterà le seguenti richieste esterne dal terminale per avviare nuovamente la sessione\n\nXPipe non ha alcun controllo sul terminale e sulla provenienza di questa chiamata, quindi anche le applicazioni locali malintenzionate possono utilizzare questa funzionalità per avviare connessioni attraverso XPipe. Disabilitando questa funzionalità si evita questo scenario.
|
||||
openDocumentation=Documentazione aperta
|
||||
openDocumentationDescription=Visita la pagina dei documenti di XPipe per questo problema
|
||||
renameAll=Rinomina tutti
|
||||
|
|
|
@ -511,3 +511,4 @@ dontAllowTerminalRestart=端末の再起動を許可しない
|
|||
dontAllowTerminalRestartDescription=デフォルトでは、ターミナル・セッションはターミナル内から終了後に再開することができる。これを可能にするため、XPipeはターミナルからセッションを再び起動するための以下の外部リクエストを受け付ける。\n\nXPipeはターミナルとこの呼び出しの発信元を制御できないため、悪意のあるローカルアプリケーションはこの機能を使用してXPipe経由で接続を開始することができる。この機能を無効にすることで、このシナリオを防ぐことができる。
|
||||
openDocumentation=ドキュメントを開く
|
||||
openDocumentationDescription=この問題のXPipeドキュメントページを見る
|
||||
renameAll=すべての名前を変更する
|
||||
|
|
|
@ -511,3 +511,4 @@ dontAllowTerminalRestart=Terminal opnieuw opstarten niet toestaan
|
|||
dontAllowTerminalRestartDescription=Standaard kunnen terminalsessies opnieuw worden gestart nadat ze vanuit de terminal zijn beëindigd. Om dit mogelijk te maken, accepteert XPipe deze externe verzoeken van de terminal om de sessie opnieuw te starten\n\nXPipe heeft geen controle over de terminal en waar deze oproep vandaan komt, dus kwaadwillende lokale applicaties kunnen deze functionaliteit ook gebruiken om verbindingen via XPipe te starten. Het uitschakelen van deze functionaliteit voorkomt dit scenario.
|
||||
openDocumentation=Open documentatie
|
||||
openDocumentationDescription=Bezoek de XPipe docs pagina voor dit probleem
|
||||
renameAll=Hernoem alle
|
||||
|
|
|
@ -511,3 +511,4 @@ dontAllowTerminalRestart=Não permitir o reinício do terminal
|
|||
dontAllowTerminalRestartDescription=Por defeito, as sessões de terminal podem ser reiniciadas depois de terminarem a partir do terminal. Para permitir isso, o XPipe aceitará essas solicitações externas do terminal para iniciar a sessão novamente\n\nO XPipe não tem qualquer controlo sobre o terminal e sobre a origem desta chamada, pelo que as aplicações locais maliciosas também podem utilizar esta funcionalidade para iniciar ligações através do XPipe. Desativar esta funcionalidade evita este cenário.
|
||||
openDocumentation=Abre a documentação
|
||||
openDocumentationDescription=Visita a página de documentação do XPipe para esta questão
|
||||
renameAll=Renomeia tudo
|
||||
|
|
|
@ -511,3 +511,4 @@ dontAllowTerminalRestart=Не разрешайте перезагрузку те
|
|||
dontAllowTerminalRestartDescription=По умолчанию терминальные сессии могут быть перезапущены после их завершения изнутри терминала. Чтобы разрешить это, XPipe будет принимать такие внешние запросы от терминала, чтобы снова запустить сессию\n\nXPipe не имеет никакого контроля над терминалом и тем, откуда поступает этот вызов, поэтому вредоносные локальные приложения могут использовать эту функциональность и для запуска соединений через XPipe. Отключение этой функциональности предотвращает подобный сценарий.
|
||||
openDocumentation=Открытая документация
|
||||
openDocumentationDescription=Посетите страницу документации XPipe по этому вопросу
|
||||
renameAll=Переименовать все
|
||||
|
|
|
@ -512,3 +512,4 @@ dontAllowTerminalRestart=Terminalin yeniden başlatılmasına izin verme
|
|||
dontAllowTerminalRestartDescription=Varsayılan olarak, terminal oturumları terminal içinden sonlandırıldıktan sonra yeniden başlatılabilir. Buna izin vermek için XPipe, oturumu tekrar başlatmak üzere terminalden gelen şu harici istekleri kabul edecektir\n\nXPipe terminal ve bu çağrının nereden geldiği üzerinde herhangi bir kontrole sahip değildir, bu nedenle kötü niyetli yerel uygulamalar XPipe üzerinden bağlantı başlatmak için bu işlevi de kullanabilir. Bu işlevselliğin devre dışı bırakılması bu senaryoyu önler.
|
||||
openDocumentation=Açık dokümantasyon
|
||||
openDocumentationDescription=Bu sorun için XPipe dokümanlar sayfasını ziyaret edin
|
||||
renameAll=Tümünü yeniden adlandır
|
||||
|
|
|
@ -511,3 +511,4 @@ dontAllowTerminalRestart=不允许终端重启
|
|||
dontAllowTerminalRestartDescription=默认情况下,终端会话可以在终端内部结束后重新启动。为了做到这一点,XPipe 将接受来自终端的这些外部请求,以再次启动会话\n\nXPipe无法控制终端以及该调用的来源,因此恶意本地应用程序也可以使用该功能通过XPipe启动连接。禁用该功能可防止出现这种情况。
|
||||
openDocumentation=开放文档
|
||||
openDocumentationDescription=访问 XPipe 文档页面了解这一问题
|
||||
renameAll=重命名所有
|
||||
|
|
Loading…
Reference in a new issue