pax_global_header00006660000000000000000000000064117750012420014511gustar00rootroot0000000000000052 comment=1fbe5cdfb6e8bcbbffeee5d7f6aa291a3944a811 autorenamer-0.3/000077500000000000000000000000001177500124200136755ustar00rootroot00000000000000autorenamer-0.3/Makefile000066400000000000000000000003221177500124200153320ustar00rootroot00000000000000all: install: install -d $(DESTDIR)/usr/bin install -d $(DESTDIR)/usr/share/applications install autorenamer.py $(DESTDIR)/usr/bin/autorenamer install autorenamer.desktop $(DESTDIR)/usr/share/applications/ autorenamer-0.3/README000066400000000000000000000021071177500124200145550ustar00rootroot00000000000000AutoRenamer - a simple program to rename files so that they sort the way you want. Requires Python, GTK and GNOME libraries. The program is based on an example "iconview.py" program by Jan Bodnar, from the PyGTK tutorial at http://zetcode.com/tutorials/pygtktutorial/ A copy of an email from Jan, clarifying the license, follows: Hi Marcin, Source code is BSD licensed. Which is the most convenient license I know. Which is in my words do what you want with the code; if you mention/link to the code you used it is fine, but even this is not required. What is licensed is the content, the tutorials. They cannot be republished on other sites without permission. Regards, Jan Bodnar On Fri, Nov 25, 2011 at 11:01 PM, Marcin Owsiany wrote: > Hello, > > Can you please clarify what is the license of the source code in your > PyGTK tutorial? I've made a tiny utility based on your iconview.py and > I'd like to publish it under a free license. That would be much easier > if your code was also published under a free license :-) autorenamer-0.3/autorenamer.1000066400000000000000000000021561177500124200163050ustar00rootroot00000000000000.TH AUTORENAMER 1 "November 27, 2011" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME autorenamer \- program to rename files so they sort according to given ordering .SH SYNOPSIS .B autorenamer .SH DESCRIPTION .B autorenamer is an interactive graphical user interface program. It displays contents of a directory using icons that you can reorder using drag-and-drop. Once you are done, the program renames the files such that their alphabetical ordering is the same as the order you chose. .P If any entries are selected when "Save" is clicked, only the selected entries are renamed. Otherwise all the entries in the directory are renamed. .SH SEE ALSO .BR mv (1). .br .SH AUTHOR autorenamer was written by Marcin Owsiany . autorenamer-0.3/autorenamer.desktop000066400000000000000000000003551177500124200176150ustar00rootroot00000000000000[Desktop Entry] Type=Application Name=AutoRenamer GenericName=Reorder files by renaming Comment=Automatically rename files have them sort in given order Exec=autorenamer Terminal=false Categories=GNOME;GTK;Utility;FileTools;FileManager; autorenamer-0.3/autorenamer.py000066400000000000000000000263241177500124200166000ustar00rootroot00000000000000#!/usr/bin/python # AutoRenamer - renames files so they sort in a given order # Copyright 2011 Marcin Owsiany # Derived from an example program from the ZetCode.com PyGTK tutorial # Copyright 2007-2009 Jan Bodnar # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of the Authors nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. import gnome.ui import gnomevfs import math import gtk import os COL_PATH = 0 COL_PIXBUF = 1 COL_IS_DIRECTORY = 2 APP_NAME = "AutoRenamer" class AutoRenamer(gtk.Window): def close(self, unused_event, unused_data): if self.modified_store: return not self.pop_dialog("Discard changes?", "Do you want to exit and lose your changes?", ok_only=False, accept_save=False) else: return False def __init__(self): super(AutoRenamer, self).__init__() self.thumb_factory = gnome.ui.ThumbnailFactory(gnome.ui.THUMBNAIL_SIZE_NORMAL) self.set_size_request(650, 400) self.set_position(gtk.WIN_POS_CENTER) self.connect("delete-event", self.close) self.connect("destroy", gtk.main_quit) self.set_title(APP_NAME) self.home_directory = os.path.realpath(os.path.expanduser('~')) self.current_directory = os.path.realpath('.') self.store_modified_handle = None vbox = gtk.VBox(False, 0) toolbar = gtk.Toolbar() vbox.pack_start(toolbar, False, False, 0) self.upButton = gtk.ToolButton(gtk.STOCK_GO_UP) self.upButton.set_is_important(True) toolbar.insert(self.upButton, -1) self.homeButton = gtk.ToolButton(gtk.STOCK_HOME) self.homeButton.set_is_important(True) toolbar.insert(self.homeButton, -1) self.saveButton = gtk.ToolButton(gtk.STOCK_SAVE) self.saveButton.set_is_important(True) toolbar.insert(self.saveButton, -1) self.discardButton = gtk.ToolButton(gtk.STOCK_CANCEL) self.discardButton.set_is_important(True) toolbar.insert(self.discardButton, -1) self.dirsButton = gtk.ToolButton(gtk.STOCK_DIRECTORY) self.dirsButton.set_label("Toggle directories") self.dirsButton.set_is_important(True) toolbar.insert(self.dirsButton, -1) self.fileIcon = self.get_icon(gtk.STOCK_FILE) self.dirIcon = self.get_icon(gtk.STOCK_DIRECTORY) sw = gtk.ScrolledWindow() sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) vbox.pack_start(sw, True, True, 0) self.store = gtk.ListStore(str, gtk.gdk.Pixbuf, bool) self.fill_store() self.iconView = gtk.IconView(self.store) self.iconView.set_reorderable(True) self.iconView.set_selection_mode(gtk.SELECTION_MULTIPLE) self.upButton.connect("clicked", self.on_up_clicked) self.homeButton.connect("clicked", self.on_home_clicked) self.discardButton.connect("clicked", self.on_discard_clicked) self.dirsButton.connect("clicked", self.on_dirs_clicked) self.saveButton.connect("clicked", self.on_save_clicked) self.iconView.set_text_column(COL_PATH) self.iconView.set_pixbuf_column(COL_PIXBUF) self.iconView.connect("item-activated", self.on_item_activated) sw.add(self.iconView) self.iconView.grab_focus() self.add(vbox) self.show_all() def get_icon(self, name): theme = gtk.icon_theme_get_default() return theme.load_icon(name, 48, 0) def fill_store(self): if self.store_modified_handle: self.store.disconnect(self.store_modified_handle) self.store.clear() self.modified_store = False if self.current_directory == None: return if self.current_directory == "/": self.upButton.set_sensitive(False) else: self.upButton.set_sensitive(True) if self.current_directory == self.home_directory: self.homeButton.set_sensitive(False) else: self.homeButton.set_sensitive(True) self.saveButton.set_sensitive(False) self.discardButton.set_sensitive(False) self.initial_order = [f for f in sorted(os.listdir(self.current_directory)) if f[0] != "."] self.set_title(APP_NAME + ": " + self.current_directory) for fl in self.initial_order: full_path = os.path.join(self.current_directory, fl) if os.path.isdir(full_path): self.store.append([fl, self.dirIcon, True]) else: icon = self.fileIcon uri = gnomevfs.get_uri_from_local_path(full_path) mime = gnomevfs.get_mime_type(uri) if self.thumb_factory.can_thumbnail(uri ,mime, 0): icon = self.thumb_factory.generate_thumbnail(uri, mime) self.store.append([fl, icon, False]) self.store_modified_handle = self.store.connect("row-deleted", self.on_row_deleted) def on_row_deleted(self, treemodel, path): if self.initial_order == [e[0] for e in self.store]: self.modified_store = False self.upButton.set_sensitive(True) self.homeButton.set_sensitive(True) self.saveButton.set_sensitive(False) self.discardButton.set_sensitive(False) else: self.modified_store = True self.upButton.set_sensitive(False) self.homeButton.set_sensitive(False) self.saveButton.set_sensitive(True) self.discardButton.set_sensitive(True) def on_home_clicked(self, widget): self.current_directory = self.home_directory self.fill_store() def on_discard_clicked(self, widget): self.fill_store() def on_dirs_clicked(self, widget): directory_paths = [(offset,) for offset, item in zip(xrange(len(self.store)), self.store) if item[COL_IS_DIRECTORY]] for path in directory_paths: if self.iconView.path_is_selected(path): self.iconView.unselect_path(path) else: self.iconView.select_path(path) def selected_elements_in_order(self): selected_indexes = [path[0] for path in self.iconView.get_selected_items()] selected_indexes.sort() return [self.store[index] for index in selected_indexes] def on_save_clicked(self, widget): new_order_elements = self.selected_elements_in_order() or self.store rename_selected_only = new_order_elements is not self.store ordered_names_to_rename = [e[COL_PATH] for e in new_order_elements] num_items = len(ordered_names_to_rename) width = math.ceil(math.log10(num_items)) fmt = "%%0%dd-%%s" % width prefixed = [(fmt % (i, f)) for i, f in zip(xrange(num_items), ordered_names_to_rename)] all_names = [e[COL_PATH] for e in self.store] conflicts = set.intersection(set(all_names), set(prefixed)) if conflicts: self.pop_dialog("Cannot rename", "The following filenames conflict.", column_names=("Filename",), column_values=[(c,) for c in conflicts]) return renames = zip(ordered_names_to_rename, prefixed) if self.pop_dialog("Renames", "The following renames will be performed." + (rename_selected_only and "\nNote: only the selected entries are renamed." or ""), ok_only=False, column_names=("From", "To"), column_values=renames): for source, dest in renames: source = os.path.join(self.current_directory, source) dest = os.path.join(self.current_directory, dest) os.rename(source, dest) self.fill_store() def pop_dialog(self, title, label_text, ok_only=True, accept_save=True, column_names=None, column_values=None): label = gtk.Label(label_text) if ok_only: buttons = (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) elif accept_save: buttons = (gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT) else: buttons = (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT) dialog = gtk.Dialog(title, self, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons) dialog.vbox.props.homogeneous = False dialog.vbox.pack_start(label, False) if column_names is not None and column_values is not None: types = [str for c in column_names] store = gtk.ListStore(*types) for value in column_values: store.append(value) list_view = gtk.TreeView(store) list_view.set_reorderable(False) sw = gtk.ScrolledWindow() sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) for name, offset in zip(column_names, range(len(column_names))): list_view.append_column(gtk.TreeViewColumn(name, gtk.CellRendererText(), text=offset)) sw.add(list_view) dialog.vbox.pack_start(sw, True, True, 0) dialog.show_all() try: return dialog.run() == gtk.RESPONSE_ACCEPT finally: dialog.destroy() def on_item_activated(self, widget, item): model = widget.get_model() path = model[item][COL_PATH] isDir = model[item][COL_IS_DIRECTORY] if not isDir: return if self.modified_store: self.pop_dialog("Save or discard", "Save or discard first!") return self.current_directory = self.current_directory + os.path.sep + path self.fill_store() def on_up_clicked(self, widget): self.current_directory = os.path.dirname(self.current_directory) self.fill_store() if __name__ == '__main__': AutoRenamer() gtk.main()