Kaynağa Gözat

bumbping to 1.1.0

Nicole Portas 2 ay önce
ebeveyn
işleme
d2e2f7e850
2 değiştirilmiş dosya ile 93 ekleme ve 10 silme
  1. 1 1
      make_deb.sh
  2. 92 9
      src/main.cpp

+ 1 - 1
make_deb.sh

@@ -1,7 +1,7 @@
 #!/bin/bash
 # Run this from your project root (where visual-renamer binary is)
 
-VERSION="1.0.0"
+VERSION="1.1.0"
 ARCH="amd64"
 DEB_NAME="visual-renamer_${VERSION}_${ARCH}"
 

+ 92 - 9
src/main.cpp

@@ -14,6 +14,8 @@
 #include <iomanip>
 #include <sstream>
 #include <set>
+#include <utime.h>
+#include <time.h>
 
 namespace fs = std::filesystem;
 
@@ -77,7 +79,7 @@ struct LoadedItem {
 class RenamerWindow : public Gtk::Window {
 public:
     RenamerWindow() : m_Dispatcher() {
-        set_title("Simple Image Renamer");
+        set_title("Simple Image Renamer 1.1");
         set_default_size(1280, 850);
         set_wmclass("simpleimagerenamer", "simpleimagerenamer");
 
@@ -112,7 +114,7 @@ public:
         m_ScaleZoom.signal_value_changed().connect(sigc::mem_fun(*this, &RenamerWindow::on_size_changed));
         m_ToolbarTop.pack_start(m_ScaleZoom, Gtk::PACK_SHRINK, 5);
 
-        m_BtnUndo.set_label("Undo");
+        m_BtnUndo.set_label("Undo Rename");
         m_BtnUndo.set_sensitive(false);
         m_BtnUndo.signal_clicked().connect(sigc::mem_fun(*this, &RenamerWindow::on_undo_clicked));
         m_ToolbarTop.pack_end(m_BtnUndo, Gtk::PACK_SHRINK, 5);
@@ -123,7 +125,9 @@ public:
         m_ToolbarControls.set_margin_top(10); m_ToolbarControls.set_margin_bottom(10);
         m_FrameControls.add(m_ToolbarControls);
 
-        m_ComboMode.append("Sequential"); m_ComboMode.append("Replace");
+        m_ComboMode.append("Sequential"); 
+        m_ComboMode.append("Replace");
+        m_ComboMode.append("Change Date");
         m_ComboMode.set_active(0);
         m_ComboMode.signal_changed().connect(sigc::mem_fun(*this, &RenamerWindow::on_mode_changed));
         m_ToolbarControls.pack_start(m_ComboMode, Gtk::PACK_SHRINK, 5);
@@ -149,6 +153,13 @@ public:
         m_BoxReplace.pack_start(*Gtk::manage(new Gtk::Label("Replace:")), Gtk::PACK_SHRINK, 5);
         m_BoxReplace.pack_start(m_EntryReplace, Gtk::PACK_EXPAND_WIDGET, 5);
         m_StackModes.add(m_BoxReplace, "Replace");
+
+        // --- Change Date Mode ---
+        m_EntryDate.set_placeholder_text("YYYY-MM-DD HH:MM:SS (Empty = 1970)");
+        m_EntryDate.signal_changed().connect(sigc::mem_fun(*this, &RenamerWindow::update_preview));
+        m_BoxDate.pack_start(*Gtk::manage(new Gtk::Label("Target Date:")), Gtk::PACK_SHRINK, 5);
+        m_BoxDate.pack_start(m_EntryDate, Gtk::PACK_EXPAND_WIDGET, 5);
+        m_StackModes.add(m_BoxDate, "Date");
         
         m_ToolbarControls.pack_start(m_StackModes, Gtk::PACK_EXPAND_WIDGET, 5);
 
@@ -210,10 +221,10 @@ public:
     ~RenamerWindow() { m_stop_flag = true; if (m_WorkerThread.joinable()) m_WorkerThread.join(); }
 
 protected:
-    Gtk::Box m_VBox, m_ToolbarTop, m_ToolbarControls, m_BoxPattern, m_BoxReplace;
+    Gtk::Box m_VBox, m_ToolbarTop, m_ToolbarControls, m_BoxPattern, m_BoxReplace, m_BoxDate;
     Gtk::Frame m_FrameControls;
     Gtk::Button m_BtnOpen, m_BtnRename, m_BtnUndo;
-    Gtk::Entry m_EntryPattern, m_EntryFind, m_EntryReplace;
+    Gtk::Entry m_EntryPattern, m_EntryFind, m_EntryReplace, m_EntryDate;
     Gtk::ComboBoxText m_ComboSort, m_ComboMode;
     Gtk::Scale m_ScaleZoom;
     Gtk::SpinButton m_SpinStartNum;
@@ -300,6 +311,17 @@ protected:
         std::set<std::string> seen;
         for (auto row : m_RefListStore->children()) {
             std::string orig = row[m_Columns.m_col_filename], next = orig;
+            
+            if (mode == 2 && row[m_Columns.m_col_checked]) {
+                std::string input = m_EntryDate.get_text();
+                if (input.empty()) input = "1970-01-01 00:00:00";
+                std::stringstream mu;
+                mu << "<span font='9'><span weight='bold'>" << Glib::Markup::escape_text(orig) << "</span>\n";
+                mu << "<span foreground='#e01b24' weight='bold'>DATE INJECTION: " << Glib::Markup::escape_text(input) << "</span></span>";
+                row[m_Columns.m_col_markup] = mu.str();
+                continue;
+            }
+
             if (row[m_Columns.m_col_checked]) {
                 if (mode == 0 && !pat.empty()) {
                     std::string num = std::to_string(start + count++);
@@ -321,7 +343,58 @@ protected:
     }
 
     void on_rename_execute() {
-        UndoStep step; int mode = m_ComboMode.get_active_row_number(), start = m_SpinStartNum.get_value_as_int(), count = 0;
+        int mode = m_ComboMode.get_active_row_number();
+        
+        // Handle Date Application logic
+        if (mode == 2) {
+            std::string input = m_EntryDate.get_text();
+            if (input.empty()) input = "1970-01-01 00:00:00";
+            
+            struct tm tm = {};
+            if (!strptime(input.c_str(), "%Y-%m-%d %H:%M:%S", &tm)) {
+                m_Statusbar.push("Error: Invalid date format. Use YYYY-MM-DD HH:MM:SS");
+                return;
+            }
+            
+            time_t target_epoch = mktime(&tm);
+            char exif_buf[32];
+            strftime(exif_buf, sizeof(exif_buf), "%Y:%m:%d %H:%M:%S", &tm);
+            std::string exif_date = exif_buf;
+
+            for (auto row : m_RefListStore->children()) {
+                if (row[m_Columns.m_col_checked]) {
+                    std::string file_path = (std::string)row[m_Columns.m_col_path];
+                    
+                    // Rewrite EXIF via exiv2
+                    try {
+                        auto img = Exiv2::ImageFactory::open(file_path);
+                        if (img->good()) {
+                            img->readMetadata();
+                            Exiv2::ExifData &exifData = img->exifData();
+                            exifData["Exif.Image.DateTime"] = exif_date;
+                            exifData["Exif.Photo.DateTimeOriginal"] = exif_date;
+                            exifData["Exif.Photo.DateTimeDigitized"] = exif_date;
+                            img->setExifData(exifData);
+                            img->writeMetadata();
+                        }
+                    } catch (...) {
+                        // Fallthrough, skip EXIF if format doesn't support it or is violently corrupted
+                    }
+
+                    // Rewrite Filesystem mtime and atime
+                    struct utimbuf new_times;
+                    new_times.actime = target_epoch;
+                    new_times.modtime = target_epoch;
+                    utime(file_path.c_str(), &new_times);
+                }
+            }
+            m_Statusbar.push("Dates Updated (EXIF + FS).");
+            start_loading_folder(m_current_path); // Refresh UI to pull new metadata
+            return;
+        }
+
+        // Standard Rename Logic
+        UndoStep step; int start = m_SpinStartNum.get_value_as_int(), count = 0;
         std::string pat = m_EntryPattern.get_text();
         size_t hpos = pat.find('#');
         int pad = (hpos != std::string::npos) ? (pat.find_last_of('#') - hpos + 1) : 0;
@@ -415,7 +488,7 @@ protected:
         m_current_path = p; m_RefListStore->clear(); std::vector<fs::path> f;
         for (const auto& e : fs::directory_iterator(p)) {
             std::string ext = e.path().extension().string(); std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
-            if (ext == ".jpg" || ext == ".png" || ext == ".jpeg") f.push_back(e.path());
+            if (ext == ".jpg" || ext == ".png" || ext == ".jpeg" || ext == ".webp" || ext == ".tif" || ext == ".tiff") f.push_back(e.path());
         }
         m_total_files = f.size(); m_processed_files = 0;
         if (m_WorkerThread.joinable()) { m_stop_flag = true; m_WorkerThread.join(); }
@@ -435,13 +508,23 @@ protected:
 
     void on_open_folder_clicked() {
         Gtk::FileChooserDialog d(*this, "Open", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
-        d.set_show_hidden(true); // <--- Here's your fix
+        d.set_show_hidden(true);
         d.add_button("Cancel", Gtk::RESPONSE_CANCEL); d.add_button("Open", Gtk::RESPONSE_OK);
         if (d.run() == Gtk::RESPONSE_OK) start_loading_folder(d.get_filename());
     }
 
     void on_selection_change(bool s) { for (auto row : m_RefListStore->children()) row[m_Columns.m_col_checked] = s; update_preview(); }
-    void on_mode_changed() { m_StackModes.set_visible_child(m_ComboMode.get_active_row_number() == 0 ? "Pattern" : "Replace"); update_preview(); }
+    
+    void on_mode_changed() { 
+        int mode = m_ComboMode.get_active_row_number();
+        if (mode == 0) m_StackModes.set_visible_child("Pattern");
+        else if (mode == 1) m_StackModes.set_visible_child("Replace");
+        else if (mode == 2) m_StackModes.set_visible_child("Date");
+        
+        m_BtnRename.set_label(mode == 2 ? "Apply Target Date (EXIF+FS)" : "Apply New Names");
+        update_preview(); 
+    }
+    
     void on_cell_toggled(const Glib::ustring& p) { auto it = m_RefListStore->get_iter(Gtk::TreePath(p)); if(it) { (*it)[m_Columns.m_col_checked] = !(*it)[m_Columns.m_col_checked]; update_preview(); } }
     bool on_iconview_button_press(GdkEventButton* e) { if (e->button == 3) { m_MenuPopup.popup(e->button, e->time); return true; } return false; }
 };