Skip to content

Commit

Permalink
Implement append mode (text-like and zip files)
Browse files Browse the repository at this point in the history
  • Loading branch information
eltos committed Jan 31, 2024
1 parent a301b1f commit 0b6864f
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 32 deletions.
67 changes: 43 additions & 24 deletions PasteIntoFile/ClipboardContents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

namespace PasteIntoFile {

public class AppendNotSupportedException : ArgumentException { }

/// <summary>
/// This is the base class to hold clipboard contents, metadata, and perform actions with it
/// </summary>
Expand Down Expand Up @@ -54,7 +56,8 @@ public string DefaultExtension {
/// </summary>
/// <param name="path">Full path where to save (incl. filename and extension)</param>
/// <param name="extension">format to use for saving</param>
public abstract void SaveAs(string path, string extension);
/// <param name="append">If true, append content</param>
public abstract void SaveAs(string path, string extension, bool append = false);

/// <summary>
/// Add the content to the data object to be placed in the clipboard
Expand Down Expand Up @@ -86,7 +89,9 @@ public ImageContent(Image image) {
public override string[] Extensions => new[] { "png", "bmp", "gif", "jpg", "pdf", "tif" };
public override string Description => string.Format(Resources.str_preview_image, Image.Width, Image.Height);

public override void SaveAs(string path, string extension) {
public override void SaveAs(string path, string extension, bool append = false) {
if (append)
throw new AppendNotSupportedException();
Image image = ImagePreview(extension);
if (image == null)
throw new FormatException(string.Format(Resources.str_error_cliboard_format_missmatch, extension));
Expand Down Expand Up @@ -174,7 +179,9 @@ public VectorImageContent(Metafile metafile) {
public override string[] Extensions => new[] { "emf" };
public override string Description => Resources.str_preview_image_vector;

public override void SaveAs(string path, string extension) {
public override void SaveAs(string path, string extension, bool append = false) {
if (append)
throw new AppendNotSupportedException();
switch (extension) {
case "emf":
IntPtr h = Metafile.GetHenhmetafile();
Expand Down Expand Up @@ -241,7 +248,9 @@ public string XmlString {

public override string[] Extensions => new[] { "svg" };
public override string Description => Resources.str_preview_svg;
public override void SaveAs(string path, string extension) {
public override void SaveAs(string path, string extension, bool append = false) {
if (append)
throw new AppendNotSupportedException();
switch (extension) {
case "svg":
using (FileStream w = File.Create(path)) {
Expand All @@ -265,8 +274,17 @@ public TextLikeContent(string text) {
}
public string Text => Data as string;
public static readonly Encoding Encoding = new UTF8Encoding(false); // omit unnecessary BOM bytes
public override void SaveAs(string path, string extension) {
File.WriteAllText(path, Text, Encoding);
public override void SaveAs(string path, string extension, bool append = false) {
Save(path, Text, append);
}

public static void Save(string path, string text, bool append = false) {
using (StreamWriter streamWriter = new StreamWriter(path, append))
streamWriter.Write(EnsureNewline(text), Encoding);
}

public static string EnsureNewline(string text) {
return text.TrimEnd('\n') + '\n';
}

/// <summary>
Expand Down Expand Up @@ -295,11 +313,11 @@ public class HtmlContent : TextLikeContent {
public HtmlContent(string text) : base(text) { }
public override string[] Extensions => new[] { "html", "htm", "xhtml" };
public override string Description => Resources.str_preview_html;
public override void SaveAs(string path, string extension) {
public override void SaveAs(string path, string extension, bool append = false) {
var html = Text;
if (!html.StartsWith("<!DOCTYPE html>"))
if (!append && !html.StartsWith("<!DOCTYPE html>"))
html = "<!DOCTYPE html>\n" + html;
File.WriteAllText(path, html, Encoding);
Save(path, html, append);
}
public override void AddTo(IDataObject data) {
// prepare header
Expand Down Expand Up @@ -389,8 +407,8 @@ public override string TextPreview(string extension) {
}
}

public override void SaveAs(string path, string extension) {
File.WriteAllText(path, TextPreview(extension), Encoding);
public override void SaveAs(string path, string extension, bool append = false) {
Save(path, TextPreview(extension), append);
}
}

Expand Down Expand Up @@ -438,11 +456,10 @@ public class UrlContent : TextLikeContent {
public UrlContent(string text) : base(text) { }
public override string[] Extensions => new[] { "url" };
public override string Description => Resources.str_preview_url;
public override void SaveAs(string path, string extension) {
File.WriteAllLines(path, new[] {
@"[InternetShortcut]",
@"URL=" + Text
}, Encoding);
public override void SaveAs(string path, string extension, bool append = false) {
if (append)
throw new AppendNotSupportedException();
Save(path, "[InternetShortcut]\nURL=" + Text);
}
public override void AddTo(IDataObject data) {
data.SetData(DataFormats.Text, Text);
Expand All @@ -469,22 +486,24 @@ public List<string> FileList {

public override string[] Extensions => new[] { "zip", "m3u", "files", "txt" };
public override string Description => string.Format(Resources.str_preview_files, Files.Count);
public override void SaveAs(string path, string extension) {
public override void SaveAs(string path, string extension, bool append = false) {
switch (extension) {
case "zip":
// TODO: since zipping can take a while depending on file size, this should show a progress to the user
var archive = ZipFile.Open(path, ZipArchiveMode.Create);
foreach (var file in Files) {
if ((File.GetAttributes(file) & FileAttributes.Directory) == FileAttributes.Directory) {
AddToZipArchive(archive, Path.GetFileName(file), new DirectoryInfo(file));
} else {
archive.CreateEntryFromFile(file, Path.GetFileName(file));
using (var archive = ZipFile.Open(path, append ? ZipArchiveMode.Update : ZipArchiveMode.Create)) {
foreach (var file in Files) {
if ((File.GetAttributes(file) & FileAttributes.Directory) == FileAttributes.Directory) {
AddToZipArchive(archive, Path.GetFileName(file), new DirectoryInfo(file));
} else {
archive.CreateEntryFromFile(file, Path.GetFileName(file));
}
}
}

break;

default:
File.WriteAllText(path, FileListString, TextLikeContent.Encoding);
TextLikeContent.Save(path, FileListString, append);
break;
}
}
Expand Down
16 changes: 16 additions & 0 deletions PasteIntoFile/Dialog.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 34 additions & 6 deletions PasteIntoFile/Dialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@ protected override void OnFormClosed(FormClosedEventArgs e) {



public Dialog(string location = null, string filename = null, bool? showDialogOverwrite = null, bool? clearClipboardOverwrite = null, bool overwriteIfExists = false) {
public Dialog(
string location = null,
string filename = null,
bool? showDialogOverwrite = null,
bool? clearClipboardOverwrite = null,
bool overwriteIfExists = false,
bool append = false
) {
Settings.Default.Reload(); // load modifications made from other instance
Settings.Default.continuousMode = false; // always start in normal mode
Settings.Default.Save();
Expand Down Expand Up @@ -91,6 +98,8 @@ public Dialog(string location = null, string filename = null, bool? showDialogOv

if (saveIntoSubdir) location += @"\" + formatFilenameTemplate(Settings.Default.subdirTemplate);
txtCurrentLocation.Text = location;

chkAppend.Checked = append; // non-persistent setting
updateUiFromSettings();
Settings.Default.PropertyChanged += (sender, args) => updateUiFromSettings();

Expand Down Expand Up @@ -241,7 +250,7 @@ private void ClipboardChanged(Object sender, SharpClipboard.ClipboardChangedEven
ignore |= Clipboard.ContainsData(Program.PATCHED_CLIPBOARD_MAGIC);

if (!ignore) {
updateFilename();
if (!chkAppend.Checked) updateFilename();
save();
updateSavebutton();
}
Expand Down Expand Up @@ -328,7 +337,8 @@ private void updateContentPreview() {


private void updateSavebutton() {
btnSave.Enabled = txtFilename.Enabled = !chkContinuousMode.Checked;
txtFilename.Enabled = !chkContinuousMode.Checked || chkAppend.Checked;
btnSave.Enabled = !chkContinuousMode.Checked;
btnSave.Text = chkContinuousMode.Checked ? string.Format(Resources.str_n_saved, saveCount) : Resources.str_save;
}

Expand All @@ -354,7 +364,7 @@ string save(bool overwriteIfExists = false, bool? clearClipboardOverwrite = fals
if (overwriteIfExists) {
// Move old file to recycle bin and proceed
ExplorerUtil.MoveToRecycleBin(file);
} else {
} else if (!chkAppend.Checked) {
// Ask user for confirmation
var result = MessageBox.Show(string.Format(Resources.str_file_exists, file), Resources.app_title,
MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
Expand All @@ -375,7 +385,20 @@ string save(bool overwriteIfExists = false, bool? clearClipboardOverwrite = fals
BaseContent contentToSave = clipData.ForExtension(comExt.Text);

if (contentToSave != null) {
contentToSave.SaveAs(file, ext);
try {
contentToSave.SaveAs(file, ext, chkAppend.Checked);
} catch (AppendNotSupportedException) {
// So ask user if we should replace instead
var msg = string.Format(Resources.str_append_not_supported, comExt.Text) + "\n\n" +
string.Format(Resources.str_file_exists, file);
var result = MessageBox.Show(msg, Resources.app_title, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (result == DialogResult.Yes) {
contentToSave.SaveAs(file, ext);
} else {
return null;
}
}

} else {
return null;
}
Expand Down Expand Up @@ -429,13 +452,18 @@ private void Main_KeyPress(object sender, KeyPressEventArgs e) {
}
}

private void chkAppend_CheckedChanged(object sender, EventArgs e) {
if (disableUiEvents) return;
updateSavebutton();
}

private void chkContinuousMode_CheckedChanged(object sender, EventArgs e) {
if (disableUiEvents) return;
if (chkContinuousMode.Checked) {
var saveNow = MessageBox.Show(Resources.str_continuous_mode_enabled_ask_savenow, Resources.str_continuous_mode, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (saveNow == DialogResult.Yes) // save current clipboard now
{
updateFilename();
// for first time save, keep current filename
save();
} else if (saveNow != DialogResult.No)
chkContinuousMode.Checked = false;
Expand Down
7 changes: 5 additions & 2 deletions PasteIntoFile/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ class ArgsPaste : ArgsCommon {
[Value(0, Hidden = true)]
public string DirectoryFallback { get; set; } // alternative: directory as first value argument

[Option("overwrite", Default = false, HelpText = "Overwrite existing file without prompt. Requires --autosave=true.")]
[Option("append", Default = false, HelpText = "Append to file if it exists (and extension supports appending).")]
public bool Append { get; set; }

[Option("overwrite", Default = false, HelpText = "Overwrite existing file without prompt. Requires --autosave=true. If append is also given, this only applies in case appending fails.")]
public bool Overwrite { get; set; }

}
Expand Down Expand Up @@ -187,7 +190,7 @@ static int RunPaste(ArgsPaste args) {
showDialogOverwrite = !args.Autosave;

// launch it
Application.Run(new Dialog(directory, filename, showDialogOverwrite, args.ClearClipboard, args.Overwrite));
Application.Run(new Dialog(directory, filename, showDialogOverwrite, args.ClearClipboard, args.Overwrite, args.Append));
return Environment.ExitCode;
}

Expand Down
28 changes: 28 additions & 0 deletions PasteIntoFile/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions PasteIntoFile/Properties/Resources.de.resx
Original file line number Diff line number Diff line change
Expand Up @@ -294,4 +294,14 @@ Die Umschalttaste gedrückt halten, um diese Einstellung temporär zu invertiere
Allows to keep application window always on top (in foreground of other windows), even if not focussed.
</comment>
</data>
<data name="str_append" xml:space="preserve">
<value>Zur Datei hinzufügen</value>
</data>
<data name="str_append_not_supported" xml:space="preserve">
<value>Hinzufügen zu bestehender Datei wird für "{0}" nicht unterstützt.</value>
</data>
<data name="str_append_tooltip" xml:space="preserve">
<value>Falls die Datei bereits existiert wird der Inhalt zur Datei hinzugefügt.
(Nur für unterstützte Dateitypen)</value>
</data>
</root>
10 changes: 10 additions & 0 deletions PasteIntoFile/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -303,4 +303,14 @@ Hold SHIFT to temporarly invert this setting.</value>
Allows to keep application window always on top (in foreground of other windows), even if not focussed.
</comment>
</data>
<data name="str_append" xml:space="preserve">
<value>Append into file</value>
</data>
<data name="str_append_tooltip" xml:space="preserve">
<value>Appends the contents to the selected file, if it already exists.
(Only for supported file types)</value>
</data>
<data name="str_append_not_supported" xml:space="preserve">
<value>Appending is not supported for extension "{0}".</value>
</data>
</root>

0 comments on commit 0b6864f

Please sign in to comment.