The name game

There are a gazillion renaming scripts out there… and now there are a gazillion + 1 renaming tools. If you’ve been using Maya for some time I’m going to assume you already have something to scratch whatever renaming itch you might have, but I decided to group the things I find I need the most. Feel free to use or abuse it as always 🙂

nameTools

  • Rename: This renames whatever object you have selected. If you have more than one object selected, it’ll rename everything in your selection and lets Maya deal with making sure none of the transforms have the same name. This might be handy if you have a hierarchy of objects and you want to name both the parent and child nodes the same name. I don’t really know why you would ever want to do that, but you might be feeling adventurous 🙂
  • Search and replace: You know what this does. I basically added this because I liked having a button to switch around the Search for and Replace with fields. And sometimes I needed to replace parts of a name in many objects in a scene. Having to select them all first was a bit of a pain in the ass. That’s why you can replace parts of the name without having to select everything first.
  • Prefix and suffix: Allows you to add something to the beginning or the end of your selection. Handy to add “left_” or “right_” to a joint chain for example.
  • Trim: This cuts x amount of characters of the beginning or end of a name.
  • Add number: This is something I use quite a lot when rigging. Let’s say you have a joint chain for the fingers on a character. The joints are named “joint1”, “joint2”, “joint3”, “joint4”, … renaming them all to something like “left_index_finger_joint_01”, “left_index_finger_joint_02”, … will get pretty tiresome. It even bothered me just typing it now 🙂 So with this function you can just select all the joints you want to rename, pick a name, a starting number and how many zeros you want to pad the number with and rename them all at once. It’s a real time saver.
  • Select by containing string: remember that one time I had to find god knows how many objects in my scene without know where they were? I think my Status Bar wasn’t showing at the moment, because I couldn’t think of a quick way to select them all without some scripting. Type in part of a name here and it will select everything containing the search string. Use the buttons below to select the first or last object in the selection, or to walk through them.
  • Search and group: With this you can search for a bunch of objects and immediately group them. If the group name already exists, the objects will be added to that group. If it doesn’t, a new group will be created.

Grab the script and put it in your scripts folder. To use it you can put the following Python code on your shelf:

import nameTools
nameTools.CreateUI()

Be sure to change this line so it reflects the correct location of the .ui file on your system:

#Change this path to the location of the nameTools.ui
uiFilePath = "PATHLOCATION/nameTools.ui"

You can find the complete source code below:



##############################################
#
#
# nameTools.py
# nielsvaes@gmail.com
#
#
##############################################



#PySide
from PySide.QtCore import * 
from PySide.QtGui import *
from PySide import QtGui as QTGui
from PySide.QtUiTools import *
from shiboken import wrapInstance


#Maya
import maya.cmds as cmds
import maya.mel as mel
import pymel.core as pm
from maya import OpenMayaUI as omui

#Python std lib
import os

ui = None

#foundObjects is used in SearchAndSelect() to iterate over the list 
foundObjects = []

#listIndex is used for Next and Previous in Search And Select
listIndex = 0



#Change this path to the location of the nameTools.ui
uiFilePath = "PATHLOCATION/nameTools.ui"

def CreateUI():
	global ui
	global uiFilePath

	mayaMainWindowPtr = omui.MQtUtil.mainWindow()
	mayaMainWindow = wrapInstance(long(mayaMainWindowPtr), QWidget)

	loader = QUiLoader()
	file = QFile(uiFilePath)
	file.open(QFile.ReadOnly)

	ui = loader.load(file, parentWidget = mayaMainWindow)
	file.close()

	ui.btnRenameTo.clicked.connect(RenameTo)
	ui.btnSwitchSearchAndReplace.clicked.connect(SwitchSearchAndReplace)
	ui.btnSearchAndReplaceRename.clicked.connect(SearchAndReplaceRename)
	ui.btnPrefixSuffixRename.clicked.connect(PrefixSuffixRename)
	ui.btnTrim.clicked.connect(Trim)
	ui.btnAddNumberRename.clicked.connect(AddNumberRename)
	
	ui.btnSearchAndSelect.clicked.connect(SearchAndSelect)
	ui.btnFirst.clicked.connect(SelectFirst)
	ui.btnLast.clicked.connect(SelectLast)
	ui.btnPrevious.clicked.connect(SelectPrevious)
	ui.btnNext.clicked.connect(SelectNext)

	ui.btnSearchAndGroup.clicked.connect(SearchAndGroup)

	ui.btnClearAll.clicked.connect(ClearAll)

	ui.setWindowFlags(Qt.Window)
	ui.show()

def RenameTo():
	newName = ui.txtRenameTo.text()

	#we're going through the list in reverse because of long naming conventions
	for selectedObject in GetSelectedLongNameObjectsReversed():
		cmds.rename(selectedObject, newName)


def SwitchSearchAndReplace():
	searchString = str(ui.txtSearchForReplace.text())
	replaceString = str(ui.txtReplaceWith.text())

	ui.txtSearchForReplace.setText(replaceString)
	ui.txtReplaceWith.setText(searchString)

def SearchAndReplaceRename():
	searchString = str(ui.txtSearchForReplace.text())
	replaceString = str(ui.txtReplaceWith.text())

	objectsToRename = []

	# first make sure the strings aren't empty
	if searchString == "" or replaceString == "":
		cmds.warning("Search and/or replace fields can't be empty!")
		return

	if ui.chkContainRenamingToSelection.isChecked():
		objectsToRename = GetSelectedLongNameObjectsReversed()
	else:
		objectsToRename = cmds.ls(type = "transform", long = True)
		objectsToRename.reverse()

	for objectToRename in objectsToRename:
		if searchString in objectToRename:
			objectToRenameShort = GetShortName(objectToRename)
			newName = objectToRenameShort.replace(searchString, replaceString)
			cmds.rename(objectToRename, newName)

def PrefixSuffixRename():
	prefix = str(ui.txtPrefix.text())
	suffix = str(ui.txtSuffix.text())

	for selectedObject in GetSelectedLongNameObjectsReversed():
		objectToRenameShort = GetShortName(selectedObject)
		cmds.rename(selectedObject, prefix + objectToRenameShort + suffix)

def Trim():
	numberOfCharacters = ui.spinNumberOfCharacters.value()

	for selectedObject in GetSelectedObjects():
		if ui.radBegin.isChecked():
			cmds.rename(selectedObject, selectedObject[numberOfCharacters:])
		else:
			cmds.rename(selectedObject, selectedObject[:-numberOfCharacters])

def AddNumberRename():

	## This works... I don't like the way it works, but it does.
	## unfortunately, it's almost 1am in the morning now and I don't want to think about his anymore
	## If, one day, I'm brave enough to get back here, I'll be sure to fix this up and make it work nicely

	if ui.txtAddNumberName.text() == "":
		cmds.warning("New name can't be empty!")
		return

	startingNumber = ui.spinStartingNumber.value()
	leadingZeros = ui.spinLeadingZeros.value()
	newName = ui.txtAddNumberName.text()

	amountOfSelectedObjects = len(GetSelectedLongNameObjectsReversed())

	startingNumber -= 1

	for selectedObject in GetSelectedLongNameObjectsReversed():
		cmds.rename(selectedObject, newName + str(amountOfSelectedObjects - startingNumber).zfill(leadingZeros + 1))
		
		startingNumber += 1

def SearchAndSelect():
	searchString = ui.txtSearchForName.text()

	# if there's nothing in the textfield, just deselect everything and return
	if searchString == "":
		cmds.select(deselect = True)
		return

	# make sure that whatever we put in foundObjects is saved to the global list
	global foundObjects

	# reset the global listIndex
	global listIndex
	listIndex = 0

	# clear the list first, there might have been something else in there that we may not want
	foundObjects = []
	# also, make sure that nothing is selected
	cmds.select(deselect = True)

	if ui.chkIgnoreCase.isChecked():
		try:
			# get all transforms in the scene
			foundObjects = cmds.ls(type = "transform")
			for foundObject in foundObjects:
				# we're ignoring case, so we're making everything lowercase
				if searchString.lower() in foundObject.lower():
					# we've found an object, so add it to the current selection
					cmds.select(foundObject, add = True)
			# the global foundObjects list is whatever we have in our selection at this point
			foundObjects = cmds.ls(selection = True)
		except:
			pass

	else:
		try:
			# we don't care about casing right now, so we cant just list every transform that contains our search string
			foundObjects = cmds.ls("*" + searchString + "*", type = "transform")
			for foundObject in foundObjects:
				cmds.select(foundObject, add = True)
		except:
			cmds.warning("No objects contain the search string: " + searchString)

def SelectFirst():
	listIndex = 0
	global foundObjects

	cmds.select(foundObjects[listIndex])

def SelectLast():
	listIndex = len(foundObjects) - 1
	global foundObjects

	cmds.select(foundObjects[listIndex]) #list[-1] selects the last item in the list, -2 the second last, etc...

def SelectPrevious():
	global foundObjects
	global listIndex

	listLength = len(foundObjects)

	if listLength == 0:
		return

	listIndex -= 1
	
	if listIndex < 0:
		listIndex = listLength - 1

	cmds.select(foundObjects[listIndex])

def SelectNext():
	global foundObjects
	global listIndex

	listLength = len(foundObjects)

	listIndex += 1

	if listIndex > listLength - 1:
		listIndex = 0

	cmds.select(foundObjects[listIndex])

def SearchAndGroup():
	searchString = ui.txtSearchForAndGroup.text()
	groupName = ui.txtGroupName.text()
	foundTransforms = []

	if searchString == "" or groupName == "":
		cmds.warning("Search for and Group Name can't be empty!")
		return

	if ui.chkIgnoreCaseGroup.isChecked():
		try:
			# get all transforms in the scene
			allTransforms = cmds.ls(type = "transform")
			for transform in allTransforms:
				# we're ignoring case, so we're making everything lowercase
				if searchString.lower() in transform.lower():
					foundTransforms.append(transform)
		except:
			pass	

	else:
		try:
			allTransforms = cmds.ls("*" + searchString + "*", type = "transform")
			for transform in allTransforms:
				foundTransforms.append(transform)
		except:
			pass

	if cmds.objExists(groupName):
		cmds.parent(foundTransforms, groupName)
	else:
		cmds.group(foundTransforms, name = groupName)

def ClearAll():
	lineEdits = ui.centralwidget.findChildren(QTGui.QLineEdit)
	
	for lineEdit in lineEdits:
		lineEdit.setText("")

def GetSelectedLongNameObjects():
	objectList = cmds.ls(selection = True, long = True)
	return objectList

def GetSelectedLongNameObjectsReversed():
	objectList = cmds.ls(selection = True, long = True)
	objectList.reverse()
	return objectList

def GetSelectedObjects():
	objectList = cmds.ls(selection = True)
	return objectList

def GetSelectedObjectsReversed():
	objectList = cmds.ls(selection = True)
	objectList.reverse()
	return objectList

def GetLongNamePart(name):
	newName = name.rsplit('|', 1)
	return newName[0]

def GetShortName(name):
	newName = name.rsplit('|', 1)
	return newName[1]

#CreateUI()