macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

An Introduction to RubyCocoa, Part 2
Pages: 1, 2, 3

This method displays an NSOpenPanel that allows the user to select multiple files to be placed into the new archive. Thus, the first thing we need to do is create an instance of the NSOpenPanel class. This is exactly what we do on the first line of the method. This line also shows us how the invocation of a Cocoa method looks in Ruby.

In this line we call the openPanel method of the NSOpenPanel class that can be found in the OSX module of the RubyCocoa framework. Since we included the module in our class, we don't have to prefix the NSOpenPanel class with the module name (e.g., OSX::NSOpenPanel). Instead all of the classes and methods of the OSX module are mixed-in to our Controller class.

The next line sets the panel to accept multiple selections, allowing the user to select as many files as he/she pleases. After that, we display our newly created panel to the user and await his or her response. Once the user has disengaged the NSOpenPanel, we check the button that was clicked and make sure the user clicked "OK" before proceeding. If so, we get the names of the files selected and cycle through them adding each file to the @files array. Now that we've added all of the files to the array, we reload the data into the table. This will display all of the elements currently in our @files array.

The removeFile method is just as simple as the addFile method, as you can clearly see from its implementation below:

###

# removeFile

#  Removes the selected file(s) from the list

#  of files for the archive.

###

def removeFile(sender)

	# Get all of the selected indices from the

	# table, and convert it to a Ruby array

	indices = @fileTableView.

		selectedRowEnumerator.allObjects.to_a

	# Get the number of indices in the array

	count = indices.length - 1



	# Reverse the order of the array before

	# removing the elements to avoid changing

	# the index number of the elements we wish

	# to remove. (e.g., if we have an array

	# [a,b,c] and we are removing elements at

	# indexes 1 and 2 we run into a problem.

	# Once element b is removed element c

	# shifts to position 1 and is not removed

	# at the second call to delete_at.)

	indices = indices.reverse



	# Remove all of the selected files

	for i in 0..count

		@files.delete_at(

			Integer(indices[i]))

	end

	@fileTableView.reloadData

end

The removeFile method starts off by getting an array of the indices of the selected elements in the table that the user has chosen for deletion. We then cycle through the list of indices deleting the element in the array at the position described by the current index.

@files array is to reverse the order of the indices, so that we start deleting items from the end of the array and progress towards the beginning. The reason for doing this is to avoid altering the index of an element by deleting another element before it and shifting the latter element forward to a lower index. If we delete from the last index back, we shift only the elements after the ones that we wish to remove, thus we avoid deleting the wrong elements in our array.

Now we have all of the code we need to allow the user to manipulate the files table in our application. If you wish, go ahead and try it out just to make sure the "+" and "-" buttons work properly. However, you will run into one problem — nothing happens. The reason for this is that we haven't told the NSTableView object that our Controller class is its data source.

We can easily do that by switching back over to IB for a second and double-clicking the NSTableView in our application until a thick line appears around it. Then control-click the table and drag a connection line to the instance of our Controller class in the "MainMenu.nib" window. In the "Info" window select "dataSource" in the "Outlets" tab of the "Connections" panel and click the "Connect" button. Now save the nib file in IB and return to Xcode and try running the application again. This time we should be able to add and remove files from our table without any problems.

We have the ability to add and remove files from our files table working properly, and there's only one method left to implement in the "Create" tab. We need to implement the method that will create the actual archive file and perhaps compress it if the user has chosen to do so.

The createArchive method needs to start off by displaying an NSSavePanel that allows the user to choose a name and a location for the new archive. After getting this information, our createArchive method is going to create a temporary directory and copy all of the selected files into it. Then the temporary directory will be tarred and compressed and copied to its chosen location.

Finally, our createArchive method will do a little cleaning up afterwards by removing the temporary folder and all of its contents. If all goes well, the user should receive an NSAlert message letting them know everything executed properly. The following code does all of this and needs to be copied into our application.

###

# createArchive

#  Displays an instance of the NSSavePanel and

#  gets a filename and location for the

#  archive file being created.

###

def createArchive(sender)

	sPanel = NSSavePanel.savePanel

	sPanel.setExtensionHidden true

	sPanel.setAccessoryView @fileTypeView

	filename = NSString.alloc.initWithString(

		"Untitled")

	buttonClicked = sPanel.runModal



	if buttonClicked == NSOKButton

		filetype =

			@fileType.titleOfSelectedItem.to_s

		directory = sPanel.filenames.

			objectAtIndex(0).to_s.split('/');

		filename = directory.pop

		directory = directory.join("/")



		# Call to_s to turn an NSString into a

		# Ruby string before performing a case

		# statement on the value

		case filetype.to_s

			when "tgz"

				tarCommand = "tar -cvzf " +

				"#{filename}.tgz #{filename}"

			when "bz2"

				tarCommand = "tar -cvjf " +

				"#{filename}.bz2 #{filename}"

			when "Z"

				tarCommand = "tar -cvZf " +

				"#{filename}.Z #{filename}"

			when "tar"

				tarCommand = "tar -cvf " +

				"#{filename}.tar #{filename}"

		end



		# Create an alert dialog to display

		# the outcome of the tar command

		alert = NSAlert.alloc.init

		alert.setMessageText(

			"Creation Successful")

		alert.setInformativeText(

			"The tar file was successfully " +

			"created")

		alert.setAlertStyle(

			NSInformationalAlertStyle)

		alert.addButtonWithTitle("Ok")



		begin

			# Create a temporary directory to

			# hold the files for the archive

			system("mkdir #{filename}")



			# Copy all of the selected files

			# to the archive directory

			@files.each do |file|

				system("cp '#{file.to_s}' " +

					"'#{filename}'")

			end



			# Execute the tar command

			system(tarCommand)



			# Copy the tar file to the chosen

			# directory

			system("mv " +

				"'#{filename}.#{filetype}' " +

				"'#{directory}/#{filename}." +

				"#{filetype}'")



			# Remove the temporary directory

			system("rm -rf '#{filename}'")

		rescue

			alert.setMessageText(

				"Creation Unsuccessful")

			alert.setInformativeText(

				"An error occurred while " +

				"creating the archive file." +

				"\nMake sure you have the " +

				"correct permissions and " +

				"try again.")

			alert.setAlertStyle(

				NSCriticalAlertStyle)

		end



		# Display an alert box

		alert.beginSheetModalForWindow(

			@mainWindow,

			:modalDelegate, self,

			:didEndSelector, nil,

			:contextInfo, nil)



	end

end

Pages: 1, 2, 3

Next Pagearrow