Explorar el Código

Corrected bug

Nicole Portas hace 1 mes
padre
commit
94f1db34ae
Se han modificado 1 ficheros con 58 adiciones y 55 borrados
  1. 58 55
      src/main.cpp

+ 58 - 55
src/main.cpp

@@ -56,7 +56,7 @@ struct LoadedItem {
 class RenamerWindow : public Gtk::Window {
 public:
     RenamerWindow() : m_Dispatcher() {
-        set_title("Simple Image Renamer 0.1");
+        set_title("Simple Image Renamer 0.2 (Patched)");
         set_default_size(1280, 850);
         
         m_Dispatcher.connect(sigc::mem_fun(*this, &RenamerWindow::on_worker_notification));
@@ -87,6 +87,8 @@ public:
         m_ComboSort.append("Name (Natural)");
         m_ComboSort.append("Date (Oldest First)");
         m_ComboSort.append("Date (Newest First)");
+        // [PATCH] Added Manual option
+        m_ComboSort.append("Manual (Drag & Drop)"); 
         m_ComboSort.set_active(0);
         m_ComboSort.signal_changed().connect(sigc::mem_fun(*this, &RenamerWindow::on_sort_changed));
         m_ToolbarTop.pack_start(m_ComboSort, Gtk::PACK_SHRINK, 5);
@@ -190,6 +192,13 @@ public:
         m_VBox.pack_start(m_ScrolledWindow);
 
         m_RefListStore = Gtk::ListStore::create(m_Columns);
+        
+        // [PATCH] Connect signal to update sequence numbers on Drag & Drop
+        m_RefListStore->signal_row_inserted().connect([this](const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&){
+            // When a row is dropped (inserted), refresh the numbering
+            update_preview(); 
+        });
+
         m_IconView.set_model(m_RefListStore);
         
         // Manual Packing for Layout
@@ -213,18 +222,23 @@ public:
         m_IconView.set_row_spacing(15);
         m_IconView.set_tooltip_column(m_Columns.m_col_path.index());
 
+        // [PATCH] Enable Reordering
+        m_IconView.set_reorderable(true); 
+
         m_ScrolledWindow.add(m_IconView);
 
         // ===========================
         // 4. STATUS BAR
         // ===========================
-        m_Statusbar.push("Welcome to Simple Image Renamer 0.1");
+        m_Statusbar.push("Welcome to Simple Image Renamer 0.2");
         m_VBox.pack_end(m_Statusbar, Gtk::PACK_SHRINK);
 
-        // --- Drag & Drop ---
+        // --- Drag & Drop (External Files) ---
         std::vector<Gtk::TargetEntry> listTargets = { Gtk::TargetEntry("text/uri-list") };
-        drag_dest_set(listTargets, Gtk::DEST_DEFAULT_ALL, Gdk::ACTION_COPY);
-        signal_drag_data_received().connect(sigc::mem_fun(*this, &RenamerWindow::on_drag_data_received));
+        // Note: For internal reordering, set_reorderable(true) handles it. 
+        // We only use this signal for files dragged from outside (Nautilus/Explorer).
+        m_IconView.drag_dest_set(listTargets, Gtk::DEST_DEFAULT_ALL, Gdk::ACTION_COPY);
+        m_IconView.signal_drag_data_received().connect(sigc::mem_fun(*this, &RenamerWindow::on_drag_data_received));
 
         show_all_children();
         // Hide the non-active mode initially
@@ -299,7 +313,7 @@ protected:
         if(iter) {
             bool val = !(*iter)[m_Columns.m_col_checked];
             (*iter)[m_Columns.m_col_checked] = val;
-            update_preview(); // Refresh preview (optional, but consistent)
+            update_preview(); 
         }
     }
 
@@ -310,7 +324,6 @@ protected:
 
     // --- PREVIEW LOGIC (Live Update) ---
     void update_preview() {
-        // Debounce could be added here for huge lists, but for <2000 items direct update is fine.
         int mode = m_ComboMode.get_active_row_number(); // 0=Pattern, 1=Replace
         
         std::string pattern = m_EntryPattern.get_text();
@@ -338,13 +351,12 @@ protected:
             bool checked = row[m_Columns.m_col_checked];
             
             if (!checked) {
-                // If not checked, just show original name in grey
                 row[m_Columns.m_col_markup] = Glib::Markup::escape_text(original);
                 continue;
             }
 
             selected_count++;
-            std::string new_name = original; // Default if logic fails
+            std::string new_name = original; 
 
             if (mode == 0 && !pattern.empty()) {
                 // PATTERN LOGIC
@@ -391,20 +403,12 @@ protected:
 
     // --- EXECUTE RENAME ---
     void on_rename_execute() {
-        // Collect moves based on current Preview logic
-        // We can actually just regenerate the names to be safe.
-        
-        // 1. Validate
         int count = 0;
         for (auto row : m_RefListStore->children()) if (row[m_Columns.m_col_checked]) count++;
         if (count == 0) return;
 
-        // 2. Generate Plan
         UndoStep undo_step;
-        std::vector<std::pair<std::string, std::string>> pending_renames; // current_path, new_name
-
-        // Reuse preview logic to determine targets
-        // (Copied strictly for safety to ensure What You See Is What You Get)
+        
         int mode = m_ComboMode.get_active_row_number();
         std::string pattern = m_EntryPattern.get_text();
         int start_num = m_SpinStartNum.get_value_as_int();
@@ -419,10 +423,9 @@ protected:
         }
 
         int iter_count = 0;
-        auto children = m_RefListStore->children();
         
         // PREPARE
-        for (auto row : children) {
+        for (auto row : m_RefListStore->children()) {
             if (!row[m_Columns.m_col_checked]) continue;
 
             std::string original_filename = row[m_Columns.m_col_filename];
@@ -444,7 +447,7 @@ protected:
             } else if (mode == 1 && !find_str.empty()) {
                 size_t pos = original_filename.find(find_str);
                 if (pos != std::string::npos) {
-                    new_filename = original_filename; // copy
+                    new_filename = original_filename; 
                     new_filename.replace(pos, find_str.length(), replace_str);
                 }
             }
@@ -466,8 +469,7 @@ protected:
              return;
         }
 
-        // 3. EXECUTE with Temp Safety
-        // To prevent collisions (renaming 1.jpg to 2.jpg while 2.jpg exists), rename all to temp first
+        // EXECUTE with Temp Safety
         std::vector<std::pair<std::string, std::string>> final_stage;
         
         int temp_idx = 0;
@@ -492,11 +494,9 @@ protected:
             }
         }
 
-        // 4. Update Undo Stack
         m_UndoStack.push(undo_step);
         m_BtnUndo.set_sensitive(true);
 
-        // 5. Reload
         start_loading_folder(m_current_path);
     }
 
@@ -507,11 +507,9 @@ protected:
         m_UndoStack.pop();
         if (m_UndoStack.empty()) m_BtnUndo.set_sensitive(false);
 
-        // Revert is tricky because of collisions. We use the temp strategy again.
         std::vector<std::pair<std::string, std::string>> final_stage;
         int temp_idx = 0;
 
-        // 1. Move current (new_path) to temp
         for (const auto& move : last_step.moves) {
             if (fs::exists(move.new_path)) {
                 fs::path src(move.new_path);
@@ -524,7 +522,6 @@ protected:
             }
         }
 
-        // 2. Move temp to original
         for (auto& item : final_stage) {
             try { fs::rename(item.first, item.second); } catch(...) {}
         }
@@ -537,17 +534,18 @@ protected:
     void on_sort_changed() {
         if (m_RefListStore->children().empty()) return;
         
-        // Get all items out
-        std::vector<Gtk::TreeRowReference> rows;
-        // This is complex to re-sort inside ListStore without reloading images.
-        // Easiest reliable way: Reload from folder (fast enough usually) 
-        // OR implement custom sort function for the TreeModel.
-        
-        // Let's use ListStore's built-in set_sort_func for cleanliness
-        int sort_mode = m_ComboSort.get_active_row_number(); // 0=Name, 1=DateOld, 2=DateNew
+        int sort_mode = m_ComboSort.get_active_row_number(); 
+        // 0=Name, 1=DateOld, 2=DateNew, 3=Manual
+
+        // [PATCH] Manual Mode Logic
+        if (sort_mode == 3) {
+            // Disable sorting to allow drag & drop
+            m_RefListStore->set_sort_column(Gtk::TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, Gtk::SORT_ASCENDING);
+            m_Statusbar.push("Manual mode: Drag images to reorder.");
+            return;
+        }
         
         if (sort_mode == 0) {
-            // Natural Sort
             m_RefListStore->set_sort_func(m_Columns.m_col_filename, [this](const Gtk::TreeModel::iterator& a, const Gtk::TreeModel::iterator& b){
                 std::string sa = (*a)[m_Columns.m_col_filename];
                 std::string sb = (*b)[m_Columns.m_col_filename];
@@ -555,18 +553,17 @@ protected:
                 return sorter(sa, sb) ? -1 : 1;
             });
         } else {
-            // Date Sort
             m_RefListStore->set_sort_func(m_Columns.m_col_time, [sort_mode, this](const Gtk::TreeModel::iterator& a, const Gtk::TreeModel::iterator& b){
                 long long ta = (*a)[m_Columns.m_col_time];
                 long long tb = (*b)[m_Columns.m_col_time];
                 if (ta == tb) return 0;
-                if (sort_mode == 1) return (ta < tb) ? -1 : 1; // Oldest first
-                return (ta > tb) ? -1 : 1; // Newest first
+                if (sort_mode == 1) return (ta < tb) ? -1 : 1;
+                return (ta > tb) ? -1 : 1;
             });
         }
         
-        m_RefListStore->set_sort_column(m_Columns.m_col_filename, Gtk::SORT_ASCENDING); // Trigger sort
-        update_preview(); // IDs change order, so numbers change
+        m_RefListStore->set_sort_column(m_Columns.m_col_filename, Gtk::SORT_ASCENDING); 
+        update_preview(); 
     }
 
     // --- WORKER: Load Data ---
@@ -585,7 +582,6 @@ protected:
             }
         } catch (...) { return; }
 
-        // Initial Sort (Natural)
         std::sort(files.begin(), files.end(), [](const fs::path& a, const fs::path& b){
             return NaturalSort()(a.filename().string(), b.filename().string());
         });
@@ -593,7 +589,6 @@ protected:
         process_files(files, size);
     }
     
-    // --- WORKER: Reload Existing List (for resizing) ---
     void worker_thread_reload(std::vector<fs::path> files, int size) {
         process_files(files, size);
     }
@@ -605,10 +600,8 @@ protected:
             item.path = path.string();
             item.filename = path.filename().string();
             
-            // Get Time
             try {
                 auto ftime = fs::last_write_time(path);
-                // Convert to simpler count for sorting
                 item.last_write_time = ftime; 
             } catch(...) {}
 
@@ -642,15 +635,14 @@ protected:
             row[m_Columns.m_col_filename] = item.filename;
             row[m_Columns.m_col_pixbuf] = item.pixbuf;
             row[m_Columns.m_col_checked] = true;
-            row[m_Columns.m_col_markup] = Glib::Markup::escape_text(item.filename); // Init label
+            row[m_Columns.m_col_markup] = Glib::Markup::escape_text(item.filename); 
             
-            // Convert time to long long for sorting
             auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(item.last_write_time - fs::file_time_type::clock::now() + std::chrono::system_clock::now());
             row[m_Columns.m_col_time] = sctp.time_since_epoch().count();
         }
         if (!m_RefListStore->children().empty()) {
             m_BtnRename.set_sensitive(true);
-            update_preview(); // Apply current naming rules immediately
+            update_preview(); 
         }
     }
 
@@ -695,23 +687,34 @@ protected:
         if (dialog.run() == Gtk::RESPONSE_OK) start_loading_folder(dialog.get_filename());
     }
 
-    void on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int, int, const Gtk::SelectionData& selection_data, guint, guint time) {
+    // [PATCH] Update D&D to support both internal reordering and external file drops
+    void on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time) {
         std::vector<Glib::ustring> uris = selection_data.get_uris();
-        if (uris.empty()) return;
+        
+        // If URI list is empty, it might be an internal reorder (which is handled automatically by set_reorderable)
+        // OR it's a failed external drop.
+        if (uris.empty()) {
+            context->drag_finish(false, false, time);
+            return;
+        }
+
         std::string filename = Glib::filename_from_uri(uris[0]);
         if (fs::is_directory(filename)) {
             start_loading_folder(filename);
             context->drag_finish(true, false, time);
         } else {
-            start_loading_folder(fs::path(filename).parent_path().string());
-            context->drag_finish(true, false, time);
+            // Check if it's a file from outside
+            if (fs::exists(filename)) {
+                start_loading_folder(fs::path(filename).parent_path().string());
+                context->drag_finish(true, false, time);
+            }
         }
     }
 };
 
 int main(int argc, char *argv[]) {
     Glib::thread_init(); 
-    auto app = Gtk::Application::create(argc, argv, "org.gtkmm.renamer_v01");
+    auto app = Gtk::Application::create(argc, argv, "org.gtkmm.renamer_v02");
     RenamerWindow window;
     return app->run(window);
-}
+}