#!/bin/bash

###############################################################################
# MultiRename v1.7 by SFR'2015												  #
# GNU GPL v2 applies														  #
# Req.: Gtkdialog >= 0.8.3, sed, awk and usuals like grep, tr, etc...		  #
###############################################################################

# Note: filenames with a newline (0ah) are not supported!

export TEXTDOMAIN=multirename
export OUTPUT_CHARSET=UTF-8

APPNAME="MultiRename-1.7"
APPICON="/usr/share/pixmaps/multirename.png"

CURDIR="$(pwd)"
[ "$*" ] && [ -d "$*" ] && CURDIR="$(readlink -f "$*")"

TMPDIR=/tmp/MultiRename_${$}
mkdir -p "$TMPDIR"
trap 'rm -rf "$TMPDIR"' EXIT

: > $TMPDIR/list

[ "`which gtkdialog4 2>/dev/null`" ] && GTKDIALOG=gtkdialog4 || GTKDIALOG=gtkdialog

export APPNAME APPICON CURDIR TMPDIR GTKDIALOG

# This is to replace the <tree> separator | with a similarily looking character
export FAKE="`echo -e '\x00\xe2\x88\xa3'`"   # Divides (U+2223)

# =============================================================================

func_readdir() {
  [ "$varHIDDEN" = "true" ] && OPTS='' || OPTS='-not -path *\/.*'
  
  CURDIR="$(echo "${1//$FAKE/|}" | sed -e 's|/\+|/|g')"	# deduplicate /
  
  if [ -d "$CURDIR" ]; then
    { find -L "$CURDIR" -mindepth 1 -maxdepth 1 -type d $OPTS -printf "gtk-directory|%P\n";
	  find -L "$CURDIR" -mindepth 1 -maxdepth 1 ! -type d $OPTS -printf "gtk-new|%P\n"; } | \
	sed -e "s/|/$FAKE/g" -e "s/$FAKE/|/1" -e "s/$/|/" | \
	sort -fV > $TMPDIR/list
    
    echo "${CURDIR//$FAKE/|}" > ${TMPDIR}/curdir
  fi
}
export -f func_readdir

# Initial call
varHIDDEN="false"
func_readdir "${CURDIR}"

# -----------------------------------------------------------------------------

func_split() {
  # Separate name from extension
  case "$(echo "$1" | tr [:upper:] [:lower:])" in	# special cases
    *.tar.7z|*.tar.bz|*.tar.bz2|*.tar.gz2|*.tar.f|*.tar.gz|*.tar.gzip|*.depot.gz|*.tar.lz|*.tar.lzma|*.tar.lzo|*.tar.xz|*.tar.z|*.tar.zip|*.cpio.7z|*.cpio.bz|*.cpio.bz2|*.cpio.f|*.cpio.gz|*.cpio.lz|*.cpio.lzma|*.cpio.lzo|*.cpio.xz|*.cpio.z|*.cpio.zip)	# special cases
       NAME="${1%.*}"
       EXT="${NAME##*.}.${1##*.}"
       NAME="${NAME%.*}"
       DOT="."
    ;;
    *)
       NAME="${1%.*}"
       EXT="${1##*.}"
       [ "$NAME" = "$EXT" ] && { DOT=""; EXT=""; } || DOT="."
    ;;
  esac
  [ "$NAME" = "" ] && [ "$EXT" ] && { NAME="${DOT}${EXT}"; EXT=""; DOT=""; }	# hidden files
}

export -f func_split

# -----------------------------------------------------------------------------

func_escape () {
  # hmm, sed sucks at replacing some symbols, so have to escape...
  OLD_NAME="${OLD_NAME//\\/\\\\}"	# escape backslashes
  OLD_NAME="${OLD_NAME//\$/\\\$}"	# escape $
  OLD_NAME="${OLD_NAME//&/\\&}"		# escape &
  OLD_NAME="${OLD_NAME//[/\\[}"		# escape [
  OLD_NAME="${OLD_NAME//]/\\]}"		# escape ]
  OLD_NAME="${OLD_NAME//\*/\\*}"	# escape *
  NEW_NAME="${NEW_NAME//\\/\\\\}"	# escape backslashes
  NEW_NAME="${NEW_NAME//\$/\\\$}"	# escape $
  NEW_NAME="${NEW_NAME//&/\\&}"		# escape &
  NEW_NAME="${NEW_NAME//[/\\[}"		# escape [
  NEW_NAME="${NEW_NAME//]/\\]}"		# escape ]
  NEW_NAME="${NEW_NAME//\*/\\*}"	# escape *
}
export -f func_escape

# -----------------------------------------------------------------------------

func_preview() {
    case "$varMODE" in
       "$(gettext "Basename only")")			MODE=N	;;
       "$(gettext "Extension only")")			MODE=E	;;
       "$(gettext "Basename with Extension")")	MODE=NE	;;
    esac

    VAL_SEQ=${varINSERT_SEQ_START}
    
    while IFS='' read -r OLD_NAME; do
      NEW_NAME="${OLD_NAME//$FAKE/|}"
      
      func_split "$NEW_NAME"
      
      # -----------
      
      # DELETE_FIRST
      if [ "$varDELETE_FIRST" = "true" ]; then
        VAL="${varDELETE_FIRST_VALUE}"
        case "$MODE" in
          N)	[ ${VAL} -gt ${#NAME} ] && VAL=${#NAME}
				NAME="${NAME:$VAL:${#NAME}}"				
		  ;;
          E)	[ ${VAL} -gt ${#EXT} ] && VAL=${#EXT}
				EXT="${EXT:$VAL:${#EXT}}"
		  ;;
		  NE)	[ ${VAL} -gt $((${#NAME}+${#DOT}+${#EXT})) ] && VAL=$((${#NAME}+${#DOT}+${#EXT}))
				[ ${VAL} -gt ${#NAME} ] && { NAME="${NAME}${DOT}${EXT}"; EXT=""; DOT=""; }
				NAME="${NAME:$VAL:${#NAME}}"
		  ;;
        esac
      fi
	  
	  # -----------
	  
      # DELETE_LAST
      if [ "$varDELETE_LAST" = "true" ]; then
        VAL="${varDELETE_LAST_VALUE}"
        case "$MODE" in
          N)	[ ${VAL} -gt ${#NAME} ] && VAL=${#NAME}
				NAME="${NAME:0:${#NAME}-$VAL}"				
		  ;;
          E)	[ ${VAL} -gt ${#EXT} ] && VAL=${#EXT}
				EXT="${EXT:0:${#EXT}-$VAL}"
		  ;;
		  NE)	[ ${VAL} -gt $((${#NAME}+${#DOT}+${#EXT})) ] && VAL=$((${#NAME}+${#DOT}+${#EXT}))
				if [ ${VAL} -gt ${#EXT} ]; then
				  NAME="${NAME}${DOT}${EXT}"
				  EXT=""; DOT=""
				  NAME="${NAME:0:${#NAME}-$VAL}"
				else
				  EXT="${EXT:0:${#EXT}-$VAL}"
				fi
		  ;;
        esac
      fi
   
      # -----------
	  
      # PREPEND
      if [ "$varPREPEND" = "true" ] && [ "$varPREPEND_STRING" ]; then
        VAL="${varPREPEND_STRING////}"	# remove /
        case "$MODE" in
          N|NE)	NAME="${VAL}${NAME}"				;;
          E)	[ "$DOT" ] && EXT="${VAL}${EXT}"	;;
        esac      
      fi
      
      # -----------
      
      # APPEND
      if [ "$varAPPEND" = "true" ] && [ "$varAPPEND_STRING" ]; then
        VAL="${varAPPEND_STRING////}"	# remove /
        case "$MODE" in
          N)	NAME="${NAME}${VAL}"				;;
          E)	[ "$DOT" ] && EXT="${EXT}${VAL}"	;;
          NE)	if [ "$DOT" ]; then
                  EXT="${EXT}${VAL}"
                else
                  NAME="${NAME}${VAL}"
                fi
          ;;
        esac
      fi
      
      # -----------
            
      # REPLACE
      if [ "$varREPLACE" = "true" ] && [ "$varREPLACE_STRING_FROM" ]; then
        VAL_FROM="${varREPLACE_STRING_FROM////}"	# remove /
        VAL_TO="${varREPLACE_STRING_TO////}"	# remove /
        case "$MODE" in
          N)	NAME="${NAME//$VAL_FROM/$VAL_TO}"	;;
          E)	EXT="${EXT//$VAL_FROM/$VAL_TO}"	;;
          NE)	NAME="${NAME}${DOT}${EXT}"
				NAME="${NAME//$VAL_FROM/$VAL_TO}"
				func_split "$NAME"
		  ;;
        esac
      fi
       
      # -----------
      
      # DELETE_AT
      if [ "$varDELETE_AT" = "true" ]; then
        VAL="${varDELETE_AT_AMOUNT}"
        OFFSET="${varDELETE_AT_OFFSET}"
        
        case "$MODE" in
          N)	[ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#NAME}+${OFFSET}+1)) # negative offset
				[ ${OFFSET} -lt 0 ] && OFFSET=0
				[ ${OFFSET} -gt ${#NAME} ] && OFFSET=${#NAME}
				NAME="${NAME:0:$OFFSET}${NAME:${OFFSET}+${VAL}}"
		  ;;
          E)	if [ "$DOT" ]; then
				  [ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#EXT}+${OFFSET}+1)) # negative offset
				  [ ${OFFSET} -lt 0 ] && OFFSET=0
				  [ ${OFFSET} -gt ${#EXT} ] && OFFSET=${#EXT}
				  EXT="${EXT:0:$OFFSET}${EXT:${OFFSET}+${VAL}}"
				fi
		  ;;
          NE)	[ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#NAME}+${#DOT}+${#EXT}+${OFFSET}+1)) # negative offset
				[ ${OFFSET} -lt 0 ] && OFFSET=0
				[ ${OFFSET} -gt $((${#NAME}+${#DOT}+${#EXT})) ] && OFFSET=$((${#NAME}+${#DOT}+${#EXT}))
				NAME="${NAME}${DOT}${EXT}"
				NAME="${NAME:0:$OFFSET}${NAME:${OFFSET}+${VAL}}"
				func_split "$NAME"
          ;;
        esac
      fi      
      
      # -----------
            
      # INSERT
      if [ "$varINSERT" = "true" ] && [ "$varINSERT_STRING" ]; then
        VAL="${varINSERT_STRING////}"	# remove /
        OFFSET="${varINSERT_OFFSET}"
        
        case "$MODE" in
          N)	[ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#NAME}+${OFFSET}+1)) # negative offset
				[ ${OFFSET} -lt 0 ] && OFFSET=0
				[ ${OFFSET} -gt ${#NAME} ] && OFFSET=${#NAME}
				NAME="${NAME:0:$OFFSET}${VAL}${NAME:$OFFSET:${#NAME}-$OFFSET}"
		  ;;
          E)	if [ "$DOT" ]; then
				  [ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#EXT}+${OFFSET}+1)) # negative offset
				  [ ${OFFSET} -lt 0 ] && OFFSET=0
				  [ ${OFFSET} -gt ${#EXT} ] && OFFSET=${#EXT}
				  EXT="${EXT:0:$OFFSET}${VAL}${EXT:$OFFSET:${#EXT}-$OFFSET}"
				fi
		  ;;
          NE)	if [ "$DOT" ]; then
                  [ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#NAME}+${#DOT}+${#EXT}+${OFFSET}+1)) # negative offset
                  [ ${OFFSET} -lt 0 ] && OFFSET=0
                  [ ${OFFSET} -gt $((${#NAME}+${#DOT}+${#EXT})) ] && OFFSET=$((${#NAME}+${#DOT}+${#EXT}))
                  if [ ${OFFSET} -le ${#NAME} ]; then
                    NAME="${NAME:0:$OFFSET}${VAL}${NAME:$OFFSET:${#NAME}-$OFFSET}"
                  else
                    OFFSET=$((${OFFSET}-${#NAME}-${#DOT}))
                    EXT="${EXT:0:$OFFSET}${VAL}${EXT:$OFFSET:${#EXT}-$OFFSET}"
                  fi
				else
                  [ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#NAME}+${OFFSET}+1)) # negative offset
				  [ ${OFFSET} -lt 0 ] && OFFSET=0
				  [ ${OFFSET} -gt ${#NAME} ] && OFFSET=${#NAME}
				  NAME="${NAME:0:$OFFSET}${VAL}${NAME:$OFFSET:${#NAME}-$OFFSET}"
                fi
          ;;
        esac
      fi
      
      # -----------

      # INSERT_SEQ
      if [ "$varINSERT_SEQ" = "true" ]; then
        VAL=$(printf "%.${varINSERT_SEQ_DIGITS}d\n" ${VAL_SEQ})
        OFFSET="${varINSERT_SEQ_OFFSET}"
        
        case "$MODE" in
          N)	[ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#NAME}+${OFFSET}+1)) # negative offset
				[ ${OFFSET} -lt 0 ] && OFFSET=0
				[ ${OFFSET} -gt ${#NAME} ] && OFFSET=${#NAME}
				NAME="${NAME:0:$OFFSET}${VAL}${NAME:$OFFSET:${#NAME}-$OFFSET}"
		  ;;
          E)	if [ "$DOT" ]; then
				  [ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#EXT}+${OFFSET}+1)) # negative offset
				  [ ${OFFSET} -lt 0 ] && OFFSET=0
				  [ ${OFFSET} -gt ${#EXT} ] && OFFSET=${#EXT}
				  EXT="${EXT:0:$OFFSET}${VAL}${EXT:$OFFSET:${#EXT}-$OFFSET}"
				else
				  ((VAL_SEQ--))
				fi
		  ;;
          NE)	if [ "$DOT" ]; then
                  [ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#NAME}+${#DOT}+${#EXT}+${OFFSET}+1)) # negative offset
                  [ ${OFFSET} -lt 0 ] && OFFSET=0
                  [ ${OFFSET} -gt $((${#NAME}+${#DOT}+${#EXT})) ] && OFFSET=$((${#NAME}+${#DOT}+${#EXT}))
                  if [ ${OFFSET} -le ${#NAME} ]; then
                    NAME="${NAME:0:$OFFSET}${VAL}${NAME:$OFFSET:${#NAME}-$OFFSET}"
                  else
                    OFFSET=$((${OFFSET}-${#NAME}-${#DOT}))
                    EXT="${EXT:0:$OFFSET}${VAL}${EXT:$OFFSET:${#EXT}-$OFFSET}"
                  fi
				else
                  [ ${OFFSET//-/} -ne ${OFFSET} ] && OFFSET=$((${#NAME}+${OFFSET}+1)) # negative offset
				  [ ${OFFSET} -lt 0 ] && OFFSET=0
				  [ ${OFFSET} -gt ${#NAME} ] && OFFSET=${#NAME}
				  NAME="${NAME:0:$OFFSET}${VAL}${NAME:$OFFSET:${#NAME}-$OFFSET}"
                fi
          ;;
        esac
        ((VAL_SEQ++))
      fi
	     
	  # -----------
      
      # CASE
      if [ "$varCASE" = "true" ]; then        
        # tr (or bash itself) doesn't handle changing case of diacritics (UTF8), but awk does
        if [ "$varLOWER" = "true" ]; then
          case "$MODE" in
            N)	NAME="$(echo "$NAME" | awk '{print tolower($0)}')"	;;
            E)	EXT="$(echo "$EXT" | awk '{print tolower($0)}')"	;;
            NE)	NAME="$(echo "$NAME" | awk '{print tolower($0)}')"
				EXT="$(echo "$EXT" | awk '{print tolower($0)}')"	;;
          esac
        else
          case "$MODE" in
            N)	NAME="$(echo "$NAME" | awk '{print toupper($0)}')"	;;
            E)	EXT="$(echo "$EXT" | awk '{print toupper($0)}')"	;;
            NE)	NAME="$(echo "$NAME" | awk '{print toupper($0)}')"
				EXT="$(echo "$EXT" | awk '{print toupper($0)}')"	;;
          esac
        fi
      fi
      
      # -----------
      
	  OLD_NAME="${OLD_NAME//|/$FAKE}"
      NEW_NAME="${NAME//|/$FAKE}${DOT}${EXT//|/$FAKE}"
      [ "$NEW_NAME" = "$OLD_NAME" ] && NEW_NAME=""

      func_escape

      sed -i "s/\(.*|${OLD_NAME}|\).*/\1${NEW_NAME}/" $TMPDIR/list

    done <<< "$varLIST"
}
export -f func_preview

# -----------------------------------------------------------------------------

func_commit() {
  # Check for duplicates
  if [ "$(cut -f2,3 -d '|' $TMPDIR/list | tr '|' '\n' | sort | uniq -d)" ]; then
    echo -n "<b>$(gettext "One or more names are duplicated, can't proceed!")</b>" > $TMPDIR/msg
    $GTKDIALOG -p GUI_ERROR
    return 1
  fi
  
  # Are you reeeaaally sure?
  echo -n "<b>$(gettext "Are you really sure you want to proceed?")</b>" > $TMPDIR/msg
  eval $($GTKDIALOG -p GUI_CONFIRM)
  [ "$EXIT" != "yes" ] && return 1
  
  CURDIR="$(cat $TMPDIR/curdir)"
    
  : > /tmp/MultiRename.log
  
  grep -o "|.*|[^$].*" $TMPDIR/list | while IFS='' read -r ITEM; do
    OLD_NAME="$(echo "$ITEM" | cut -f2 -d '|')"
    NEW_NAME="$(echo "$ITEM" | cut -f3 -d '|')"
    if [ ! -e "${CURDIR}/${NEW_NAME//$FAKE/|}" ]; then	# PRECAUTION!!!
      mv -f "${CURDIR}/${OLD_NAME//$FAKE/|}" "${CURDIR}/${NEW_NAME//$FAKE/|}" 2>>/tmp/MultiRename.log
    else
      echo "$(gettext "Multirename: can't rename") '${OLD_NAME//$FAKE/|}' -> '${NEW_NAME//$FAKE/|}' - $(gettext "the latter already exists!")." >> /tmp/MultiRename.log
    fi
  done
  
  if [ -s /tmp/MultiRename.log ]; then
    echo -ne "<b>$(gettext "There were errors and not all files have been renamed!\nSee /tmp/MultiRename.log for details.")</b>" > $TMPDIR/msg
    $GTKDIALOG -p GUI_ERROR
  fi
  
  func_readdir "${CURDIR}"
}
export -f func_commit

# -----------------------------------------------------------------------------

func_manual_do () {
  OLD_NAME="${varMANUAL_OLD//|/$FAKE}"
  NEW_NAME="${varMANUAL_NEW//|/$FAKE}"
  NEW_NAME="${NEW_NAME////}"	# remove /
  [ "$NEW_NAME" = "$OLD_NAME" ] && NEW_NAME=""

  func_escape
  
  sed -i "s/\(.*|${OLD_NAME}|\).*/\1${NEW_NAME}/" $TMPDIR/list

}
export -f func_manual_do

# -----------------------------------------------------------------------------

func_manual () {
  [ "$varLIST" ] || return 1
  
  ITEM_COUNT="$(echo -e "$varLIST" | wc -l)"
  
  if [ $ITEM_COUNT -gt 1 ]; then
    echo -ne "<b>$(gettext "Please select only one item.")</b>" > ${TMPDIR}/msg
    $GTKDIALOG -p GUI_ERROR
    return 1
  fi

  MANUAL_OLD="${varLIST//$FAKE/|}"
  MANUAL_NEW="$(grep -F "|$(echo "${varLIST}")|" $TMPDIR/list | cut -f3- -d'|')"
  MANUAL_NEW="${MANUAL_NEW//$FAKE/|}"
  
  echo -n "$MANUAL_OLD" > $TMPDIR/manual_old
  echo -n "$MANUAL_NEW" > $TMPDIR/manual_new
	
  GUI_MANUAL='
    <window title="'${APPNAME}'" window-position="2" image-name="'${APPICON}'" resizable="true" width-request="512">
	  <vbox>
		<frame '$(gettext "Rename the item manually")'>
	      <hbox>
	        <entry editable="false" has-frame="false">
	      	  <variable>varMANUAL_OLD</variable>
	      	  <input file>"'${TMPDIR}/manual_old'"</input>
	        </entry>
	        <pixmap stock-icon-size="3"><input file stock="gtk-go-forward"></input></pixmap>
	        <entry has-focus="true">
	      	  <variable>varMANUAL_NEW</variable>
	      	  <input>[ -s "'${TMPDIR}/manual_new'" ] && cat "'${TMPDIR}/manual_new'" || cat "'${TMPDIR}/manual_old'"</input>
	        </entry>
	      </hbox>
        </frame>
            
		<hbox space-fill="false" space-expand="false">
		<button>
		 <label>"'$(gettext "Apply")'"</label>
		 <input file stock="gtk-apply"></input>
		 <action>func_manual_do</action>
		 <action>exit:exit</action>
		</button>
		<button>
		 <label>"'$(gettext "Cancel")'"</label>
		 <input file stock="gtk-cancel"></input>
		 <action>exit:exit</action>
		</button>
		</hbox>
         
		</vbox>

	  <action signal="delete-event">exit:abort</action>
	</window>'
  
  export GUI_MANUAL
  
  $GTKDIALOG -p GUI_MANUAL

}
export -f func_manual

# =============================================================================

export GUI_ERROR='
<window title="'${APPNAME}'" window-position="1" image-name="'${APPICON}'" resizable="false">
  <vbox>
    <hbox space-fill="true" space-expand="true">
      <pixmap><input file stock="gtk-dialog-error"></input></pixmap>
      <text use-markup="true"><input file>'${TMPDIR}/msg'</input></text>
    </hbox>
    <hbox>
      <button ok></button>
    </hbox>
  </vbox>
  
  <action signal="delete-event">exit:abort</action>
</window>'

# -----------------------------------------------------------------------------

export GUI_CONFIRM='
<window title="'${APPNAME}'" window-position="1" image-name="'${APPICON}'" resizable="false">
  <vbox>
    <pixmap><input file stock="gtk-dialog-question"></input></pixmap>
    <text><label>""</label></text>
    <text wrap="false" use-markup="true"><input file>'${TMPDIR}/msg'</input></text>
    <text><label>""</label></text>
    <hbox>
      <button space-fill="true" space-expand="true">
        <label>"'$(gettext "No")'"</label>
        <input file stock="gtk-no"></input>
        <action>exit:no</action>
      </button>
      <button space-fill="true" space-expand="true">
        <label>"'$(gettext "Yes")'"</label>
        <input file stock="gtk-yes"></input>
        <action>exit:yes</action>
      </button>
    </hbox>
  </vbox>

  <action signal="delete-event">exit:abort</action>
</window>'

# -----------------------------------------------------------------------------

export GUI_MAIN='
<window title="'${APPNAME}'" image-name="'${APPICON}'">
  <vbox space-fill="true" space-expand="true">
    <hbox>
      <hbox space-fill="true" space-expand="true">
        <vbox>
        
          <hbox>
            <entry space-fill="true" space-expand="true">
              <variable>varCURDIR</variable>
              <input file>'"${TMPDIR}/curdir"'</input>
              <action signal="activate">func_readdir "${varCURDIR}"</action>
              <action signal="activate">refresh:varLIST</action>
              <action signal="activate">refresh:varCURDIR</action>
              <action signal="activate">disable:varCOMMIT</action>
            </entry>
            
            <button tooltip-text="'$(gettext "Parent directory")'">
              <input file stock="gtk-go-up"></input>
              <action>func_readdir "$(dirname "$(cat $TMPDIR/curdir)")"</action>
              <action>refresh:varLIST</action>
              <action>refresh:varCURDIR</action>
              <action>refresh:varSTATUS</action>
              <action>disable:varCOMMIT</action>
            </button>
        
            <button tooltip-text="'$(gettext "Home")'">
              <input file stock="gtk-home"></input>
              <action>func_readdir "$HOME"</action>
              <action>refresh:varLIST</action>
              <action>refresh:varCURDIR</action>
              <action>refresh:varSTATUS</action>
              <action>disable:varCOMMIT</action>
            </button>
            
            <button tooltip-text="'$(gettext "Re-read current directory")'">
              <input file stock="gtk-refresh"></input>
              <action>func_readdir "$(cat $TMPDIR/curdir)"</action>
              <action>refresh:varLIST</action>
              <action>refresh:varCURDIR</action>
              <action>refresh:varSTATUS</action>
              <action>disable:varCOMMIT</action>
            </button>
            
            <togglebutton tooltip-text="'$(gettext "Show hidden files and directories")'">
              <variable>varHIDDEN</variable>
              <label>"'$(gettext "Show hidden")'"</label>
              <action>func_readdir "$(cat $TMPDIR/curdir)"</action>
              <action>refresh:varLIST</action>
              <action>refresh:varSTATUS</action>
              <action>disable:varCOMMIT</action>
            </togglebutton>
          </hbox>
          
          <tree block-function-signals="true" column-header-active="true|true" selection-mode="3" enable-search="false">
            <variable>varLIST</variable>
            <width>512</width>
            <height>390</height>
            <label>"'$(gettext "Old Name")'|'$(gettext "New Name")'"</label>
            <input file stock-column="0">'"${TMPDIR}/list"'</input>
            <action>func_readdir "$(cat $TMPDIR/curdir)/$(echo "${varLIST#*|}")"</action>
            <action>refresh:varLIST</action>
            <action>refresh:varCURDIR</action>
            <action>refresh:varSTATUS</action>
            
            <action signal="button-release-event" condition="command_is_true( [ $PTR_BTN -eq 3 ] && echo true)">func_manual</action>
            <action signal="key-release-event" condition="command_is_true( [ \"$KEY_SYM\" = \"Return\" ] && [ $(($KEY_MOD & 1)) -eq 1 ] && echo true)">func_manual</action>
            <action signal="button-release-event" condition="command_is_true( [ $PTR_BTN -eq 3 ] && echo true)">refresh:varLIST</action>
            <action signal="key-release-event" condition="command_is_true( [ \"$KEY_SYM\" = \"Return\" ] && [ $(($KEY_MOD & 1)) -eq 1 ] && echo true)">refresh:varLIST</action>
            <action signal="button-release-event" condition="command_is_true( [ $PTR_BTN -eq 3 ] && echo true)">refresh:varSTATUS</action>
            <action signal="key-release-event" condition="command_is_true( [ \"$KEY_SYM\" = \"Return\" ] && [ $(($KEY_MOD & 1)) -eq 1 ] && echo true)">refresh:varSTATUS</action>
            <action signal="button-release-event" condition="command_is_true( [ $PTR_BTN -eq 3 ] && echo true)">enable:varCOMMIT</action>
            <action signal="key-release-event" condition="command_is_true( [ \"$KEY_SYM\" = \"Return\" ] && [ $(($KEY_MOD & 1)) -eq 1 ] && echo true)">enable:varCOMMIT</action>

            <action condition="command_is_true( [ $(cut -f3- -d \"|\" $TMPDIR/list | grep -v \"^$\" | wc -l) -eq 0 ] && echo true)">disable:varCOMMIT</action>
            <action signal="button-release-event" condition="command_is_true( [ $(cut -f3- -d \"|\" $TMPDIR/list | grep -v \"^$\" | wc -l) -eq 0 ] && echo true)">disable:varCOMMIT</action>
            <action signal="key-release-event" condition="command_is_true( [ $(cut -f3- -d \"|\" $TMPDIR/list | grep -v \"^$\" | wc -l) -eq 0 ] && echo true)">disable:varCOMMIT</action>

            <action signal="changed">refresh:varSTATUS</action>
          </tree>
          
          <hbox space-fill="false" space-expand="false">
            <statusbar has-resize-grip="false" space-fill="true" space-expand="true">
              <variable>varSTATUS</variable>
              <input>echo -ne " '$(gettext "All items:")' $(cat $TMPDIR/list | wc -l)\t\t'$(gettext "Selected items:")' $([ "$varLIST" = "" ] && echo -n "0" || echo "$varLIST" | wc -l)\t\t'$(gettext "Renamed items:")' $(cut -f3- -d "|" $TMPDIR/list | grep -v "^$" | wc -l)"</input>
            </statusbar>
          </hbox>
              
        </vbox>
        
      </hbox>
      
      <hbox space-fill="false" space-expand="false">
      
        <vseparator space-fill="false" space-expand="false"></vseparator>
        <text space-fill="true" space-expand="true"><label>""</label></text>
        
        <vbox>
        
          <frame>
            <hbox>
              <text><label>"'$(gettext "Mode:")'"</label></text>
              <text space-fill="true" space-expand="true"><label>""</label></text>
              <comboboxtext>
                <variable>varMODE</variable>
                <item>"'$(gettext "Basename only")'"</item>
                <item>"'$(gettext "Extension only")'"</item>
                <item>"'$(gettext "Basename with Extension")'"</item>
              </comboboxtext>
            </hbox>
                     
            <hseparator></hseparator>

            <hbox>
              <checkbox>
                <variable>varDELETE_FIRST</variable>
                <label>"'$(gettext "Delete first")'"</label>
                <action>if true enable:varDELETE_FIRST_VALUE</action>
                <action>if false disable:varDELETE_FIRST_VALUE</action>
              </checkbox>
              <text space-fill="true" space-expand="true"><label>""</label></text>
              <spinbutton range-min="1" range-max="255" range-step="1" range-value="1" sensitive="false">
                <variable>varDELETE_FIRST_VALUE</variable>
              </spinbutton>
              <text><label>"'$(gettext "char(s)")'"</label></text>
            </hbox>
            
            <hseparator></hseparator>
            
            <hbox>
              <checkbox>
                <variable>varDELETE_LAST</variable>
                <label>"'$(gettext "Delete last")'"</label>
                <action>if true enable:varDELETE_LAST_VALUE</action>
                <action>if false disable:varDELETE_LAST_VALUE</action>
              </checkbox>
              <text space-fill="true" space-expand="true"><label>""</label></text>
              <spinbutton range-min="1" range-max="255" range-step="1" range-value="1" sensitive="false">
                <variable>varDELETE_LAST_VALUE</variable>
              </spinbutton>
              <text><label>"'$(gettext "char(s)")'"</label></text>
            </hbox>
            
            <hseparator></hseparator>
                        
            <hbox>
              <checkbox>
                <variable>varPREPEND</variable>
                <label>"'$(gettext "Prepend")'"</label>
                <action>if true enable:varPREPEND_STRING</action>
                <action>if false disable:varPREPEND_STRING</action>
              </checkbox>
              <text space-fill="true" space-expand="true"><label>""</label></text>
              <entry sensitive="false">
                <variable>varPREPEND_STRING</variable>
              </entry>
            </hbox>
            
            <hseparator></hseparator>

            <hbox>
              <checkbox>
                <variable>varAPPEND</variable>
                <label>"'$(gettext "Append")'"</label>
                <action>if true enable:varAPPEND_STRING</action>
                <action>if false disable:varAPPEND_STRING</action>
              </checkbox>
              <text space-fill="true" space-expand="true"><label>""</label></text>
              <entry sensitive="false">
                <variable>varAPPEND_STRING</variable>
              </entry>
            </hbox>
            
            <hseparator></hseparator>

            <vbox>
              <hbox>
                <checkbox>
                  <variable>varREPLACE</variable>
                  <label>"'$(gettext "Replace")'"</label>
                  <action>if true enable:varREPLACE_STRING_FROM</action>
                  <action>if true enable:varREPLACE_STRING_TO</action>
                  <action>if false disable:varREPLACE_STRING_FROM</action>
                  <action>if false disable:varREPLACE_STRING_TO</action>
                </checkbox>
                <text space-fill="true" space-expand="true"><label>""</label></text>
                <entry max-length="256" space-fill="false" space-expand="false" sensitive="false">
                  <variable>varREPLACE_STRING_FROM</variable>
                </entry>
              </hbox>
              <hbox>
                <text><label>"'$(gettext "with")'  "</label></text>
                <entry max-length="256" space-fill="false" space-expand="false" sensitive="false">
                  <variable>varREPLACE_STRING_TO</variable>
                </entry>
              </hbox>
            </vbox>
            
            <hseparator></hseparator>
            
            <vbox>
              <hbox>
                <checkbox>
                  <variable>varDELETE_AT</variable>
                  <label>"'$(gettext "Delete")'"</label>
                  <action>if true enable:varDELETE_AT_AMOUNT</action>
                  <action>if true enable:varDELETE_AT_OFFSET</action>
                  <action>if false disable:varDELETE_AT_AMOUNT</action>
                  <action>if false disable:varDELETE_AT_OFFSET</action>
                </checkbox>
                <text space-fill="true" space-expand="true"><label>""</label></text>
                <spinbutton range-min="0" range-max="255" range-step="1" range-value="1" sensitive="false">
                  <variable>varDELETE_AT_AMOUNT</variable>
                </spinbutton>
                <text><label>"'$(gettext "char(s)")'"</label></text>
              </hbox>
              <hbox>
                <text><label>"'$(gettext "at offset")'   "</label></text>
                <spinbutton range-min="-255" range-max="255" range-step="1" range-value="0" sensitive="false">
                  <variable>varDELETE_AT_OFFSET</variable>
                </spinbutton>
              </hbox>
            </vbox>  
              
            <hseparator></hseparator>
                    
            <vbox>
              <hbox>
                <checkbox>
                  <variable>varINSERT</variable>
                  <label>"'$(gettext "Insert")'"</label>
                  <action>if true enable:varINSERT_STRING</action>
                  <action>if true enable:varINSERT_OFFSET</action>
                  <action>if false disable:varINSERT_STRING</action>
                  <action>if false disable:varINSERT_OFFSET</action>
                </checkbox>
                <text space-fill="true" space-expand="true"><label>""</label></text>
                <entry max-length="256" space-fill="false" space-expand="false" sensitive="false">
                  <variable>varINSERT_STRING</variable>
                </entry>
              </hbox>
              <hbox>
                <text><label>"'$(gettext "at offset")'   "</label></text>
                <spinbutton range-min="-255" range-max="255" range-step="1" range-value="0" sensitive="false">
                  <variable>varINSERT_OFFSET</variable>
                </spinbutton>
              </hbox>
            </vbox>
            
            <hseparator></hseparator>
            
            <vbox>
              <hbox>
                <checkbox>
                  <variable>varINSERT_SEQ</variable>
                  <label>"'$(gettext "Insert")'"</label>
                  <action>if true enable:varINSERT_SEQ_DIGITS</action>
                  <action>if true enable:varINSERT_SEQ_OFFSET</action>
                  <action>if true enable:varINSERT_SEQ_START</action>
                  <action>if false disable:varINSERT_SEQ_DIGITS</action>
                  <action>if false disable:varINSERT_SEQ_OFFSET</action>
                  <action>if false disable:varINSERT_SEQ_START</action>
                </checkbox>
                <text space-fill="true" space-expand="true"><label>""</label></text>
                <spinbutton range-min="1" range-max="16" range-step="1" range-value="1" sensitive="false">
                  <variable>varINSERT_SEQ_DIGITS</variable>
                </spinbutton>
                <text><label>"'$(gettext "\-digit sequence")'"</label></text>
              </hbox>
              <hbox>
                <text><label>"'$(gettext "starting from")'   "</label></text>
                <spinbutton range-min="0" range-max="1000000000000000" range-step="1" range-value="1" sensitive="false">
                  <variable>varINSERT_SEQ_START</variable>
                </spinbutton>    
              </hbox>
              <hbox>
                <text><label>"'$(gettext "at offset")'   "</label></text>
                <spinbutton range-min="-255" range-max="255" range-step="1" range-value="0" sensitive="false">
                  <variable>varINSERT_SEQ_OFFSET</variable>
                </spinbutton>              
              </hbox>
            </vbox>
                        
            <hseparator></hseparator>
     
            <hbox>
              <checkbox>
                <variable>varCASE</variable>
                <label>"'$(gettext "Case to")'"</label>
                <action>if true enable:varLOWER</action>
                <action>if true enable:varUPPER</action>
                <action>if false disable:varLOWER</action>
                <action>if false disable:varUPPER</action>
              </checkbox>
              <text space-fill="true" space-expand="true"><label>""</label></text>
              <radiobutton sensitive="false">
                <variable>varLOWER</variable>
                <label>"'$(gettext "Lower")'"</label>
              </radiobutton>
              <radiobutton sensitive="false">
                <variable>varUPPER</variable>
                <label>"'$(gettext "Upper")'"</label>
              </radiobutton>
            </hbox>
            
          </frame>
          
          <hbox space-fill="false" space-expand="false">
            <button space-fill="true" space-expand="true" tooltip-text="'$(gettext "Preview renamed items")'">
              <label>"'$(gettext "Preview")'"</label>
              <input file stock="gtk-find"></input>
              <action>func_preview</action>
              <action>refresh:varLIST</action>
              <action>refresh:varSTATUS</action>
              <action>disable:varCOMMIT</action>
              <action condition="command_is_true( [ $(cut -f3- -d \"|\" $TMPDIR/list | grep -v \"^$\" | wc -l) -gt 0 ] && echo true)">enable:varCOMMIT</action>
            </button>
            
            <button space-fill="true" space-expand="true" sensitive="false" tooltip-text="'$(gettext "Commit all the changes")'">
              <variable>varCOMMIT</variable>
              <label>"'$(gettext "Commit")'"</label>
              <input file stock="gtk-apply"></input>
              <action>func_commit</action>
              <action>refresh:varLIST</action>
              <action>refresh:varSTATUS</action>
              <action condition="command_is_true( [ $(cut -f3- -d \"|\" $TMPDIR/list | grep -v \"^$\" | wc -l) -eq 0 ] && echo true)">disable:varCOMMIT</action>
            </button>
            
            <vseparator></vseparator>
            
            <button tooltip-text="'$(gettext "Quit")'">
              <input file stock="gtk-quit"></input>
              <action>exit:exit</action>
            </button>
            
          </hbox>
          
        </vbox>
        
      </hbox>
        
    </hbox>
    
  </vbox>

  <action signal="show">disable:varCURDIR</action>
  <action signal="show">enable:varCURDIR</action>
  <action signal="delete-event">exit:abort</action>
</window>'

$GTKDIALOG -p GUI_MAIN

# =============================================================================

exit
