Datafile problems

Ok, I’ve got several things I need help on so this is going to be a long post.

I’m working on a AppleScript Studio application and for the last day or so I’ve been searching learning and doing more and more but I’ve finally hit a wall and need help. Not just with the AppleScript side but maybe there are better easier way to do some things I’m trying to do.

This application basically is going to read data from a text file, builds a pop up menu with that data and when an item of the menu is selected it will place the data into two text fields. With my days worth of work I’ve managed to make a text file formatted like below and get the name into a variable called ShipType and the two numbers into variables into ShipCrew and ShipS with this code:

try
	set dataFile to (open for access file path:to:file with write permission)
end try
try
	set theText to items of (read dataFile using delimiter ",")
end try
try
	set CountNum to (count of theText)
on error
	beep
end try
close access dataFile
try
	set ShipType to the first item of theText
	set ShipCrew to the second item of theText as number
	set ShipS to the last item of theText as number
end try

Text file (Note that the Thing 1 place might be a multiword name):

Thing 1,200,500

First off if there is an easier way to do what I did above I would be glad to hear it. So I’m stuck in two places. First I’ve only figured out how to read from one line. I would like to hit return and put in another line for the next thing and so on with no hard coded limit for the number of items to import. I can’t think of anyway to do this yet. Again I’m not set on this particular way of formating the file, if doing it a different way would be easier I’m all for it.

Example of file I want to import:

Thing 1,200,500
Thing2,2,1
Thing3,678,325
Thing 4,56,64

Second I want to populate a pop up button list with the data from the file. Specifically I want the names to be listed and when the user selects one of the items in the list it will put the two numbers into separate text fields. Currently my pop up button is named Menu1 and the first number need to go into a text field named PlayerC and the second number to PlayerS. Currently my menu code is set up like this:

on choose menu item theObject
	tell window of theObject
		set PlayerStrength to title of current menu item of popup button �
			"Menu1"
		if PlayerStrength is "Thing 1" then
			set the contents of text field "PlayerS" to 2
			set the contents of the text field "PlayerC" to 1

The program then goes on the reference those text fields and does math with the numbers but I’m pretty sure that doesn’t need changing. So, I know that a lot of questions but any help would be appreciated, thanks.

What’s the scope of your database? In other words, are you looking to store hundreds of lines of data with massive ‘text’ entries, or are you just setting preferences or simple, short records? If you don’t have tons of data to write, perhaps using your app’s plist would be more appropriate. You can save lists of data into the plist file and access them quite easily. Plus, the plist file is already there so you don’t need to manually create it or deal with getting to it and managing it’s data with complex custom code. I am not sure what the data limits of the plist file are, but I think your computing overhead with some custom text-ripping code would probably be just as large or larger than accessing the plist. There are lot’s of posts here which cover plists, and I have some code which can save your list into the value of a key/value pair that I’d be happy to share :wink: .

j

Yeah, the maximum number of entries ( an entry being a name and the two numbers assoicated with that name) will be 768, but I hightly doubt anybody would use that many, if they did they’re just crazy :P. I was looking at using plist files, but wasn’t sure of how easy it would be for the users to create their own list. I figured a text file is about as easy as it can get for reading in custom data, but if I could use plist files and still retain the abality for the users to make their own list I’m all for it.

Getting your values from the UI would take the same code either way. If you’re doing math on the numbers before saving it to file, you can work your data checking into the same code so there won’t be much extra code one way vs. the other.

Your decision to use a popup button leads me to believe you don’t feel that the user will be storing a huge amount of entries. I think that when a popup button has too many items in it, it is cumbersome and hard to use. So, if there could be “768” entries in it, you may want to go with a table or outline view and sort it alphabetically, by category, or by some other criteria.

One thing to clarify is, do you want your user to be able to make THEIR OWN text file manually and “import it”, or do you want to provide the file and the mechanism for managing it within your application? If it is critical to the function of the app, you should probably place it in the app’s directory, or better yet, within its bundle. The advantage to the text file approach, is that there isn’t any extra stuff in the database (like a bunch of xml code, as in a plist). With 700+ entries, this is significant. With a “reasonable” number of entries, a plist outweighs the text file in ease of use.

The code to do the text file should be fairly straighforward. I use “flat file” databases a lot in my cgi work, and the process is not too tough. Basically, you fetch the file contents as a list. Separate it into entries by splitting it at the returns. Then repeat through the entries setting the variables and writing the menu items in the popup button using the code you’ve already started writing.

If you’re expecting just a few dozen entries, a plist is much easier in my opinion. You don’t have to mess with chopping up a data file, and deal with encoding characters that may cause problems and workarounds for special characters. There are concerns with setting data to a text file like…with the system you’ve got, what happens if the user uses a comma in their content? If you don’t check for that, your script would freak out trying to figure which comma to split the line at. CGI scripters use the “|” (pipe) symbol a lot to separate list items. You could also try saving each entry/line as a list so you wouldn’t need to worry about which separator to use. A plist is set up to just take the info you give it and plug it in automatically. I like 'em :slight_smile: They’re easy and don’t cause to many probs once you figure them out. Here’s an example of what a plist with seven string variables and a boolean looks like stored as lists (arrays)…

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>MyRecord1</key>
	<array>
		<string>Jobu</string>
		<string>www.jobu.com</string>
		<string>pubic_hml</string>
		<string>username</string>
		<string>password</string>
		<string>TRUE</string>
		<string>TRUE</string>
		</true>
	</array>
	<key>MyRecord2</key>
	<array>
		<string>dfsdfd</string>
		<string>gtrh</string>
		<string>hcvhh</string>
		<string></string>
		<string></string>
		<string>FALSE</string>
		<string>FALSE</string>
		</false>
	</array>
</dict>
</plist>

As I said, for 700 entries, the plist isn’t probably reasonable. There would be more formatting code than data. Sorry for the massive response. I’m a bit of a philosopher when it comes to posting to forums. :rolleyes:

Hope this doesn’t hurt more than it helps… :?
j

Don’t worry about the long reply. I’m trying to learn and I’m glad for a nice long informative reply.

The application doesn’t need to worry about storing results. The result is just outputted to a text field at the bottom of the window. Its meant for instant data, just fill in a few text fields and hit one of two buttons and get a result. While the maximum is that 700+ number I can’t see anybody using that many items, but the 200 to 300 range is conceivable and who knows somebody may decide to have no life and hit the 700+ mark. So that may rule the plist option out.

A text file in the bundle seems to make the most sense. What I planned to do was ship a data file with the app containing some default data which many users will use, the app is a utility to a game, so most people won’t need to change the default data. Some will want to modify the file or completely change the file with their own data. I do agree that using a | is a much better idea than what I was going with.

Sorry, I’ll make it quick this time, and then I can work on helping with some actual code. Sounds like plist is out, text is in :slight_smile:

So all you want to do with the app is read the file, not write to it, right? You want to leave the writing of the file to you and a few ambitious people who want to edit the file by hand. If so…this is good, and convenient for you, as the amount of code required is reduced significantly. Placing the file in the bundle makes it harder for average users to get to, as you must ‘control-click’ on the application to reveal the directory of it’s bundle (package) contents. If you do it this way, you’ll have to explicitly state how to get to the file to edit it. A better idea might be to distribute your app in a directory, rather than as a standalone, so you can place your file in an obvious place (like a “resources” or “data” folder, alongside your app) like…

/Applications
__/MyApp
____MyApp.app
____/Resources
_______MyTextFile.txt

This will make the location of the key data file(s) obvious and easy to reach. It also makes it easy for you to reference the file in your code because the location is local and always the same. I’ll get some code together and send it on…

j

Correct, the program will a data file I do myself as the defualt and the users can if they want edit or completely replace that file with one of their own. I really like the idea of using the data file inside the bundle itself, just becuase its cleaner. But the accessibiblity issue is a problem… I guess it would be better to keep the data file accessable in a data folder since people will want to edit it.

Sorry for the delayed response. The code turned out to be about 130 lines, so I didn’t want to waste space here. Anyone can get the code here…
Code: Read Text File Database color=#666666[/color]

Basically, it reads your pipe “|” delimited text db and sets the menu items of a popup menu to the db’s contents line-by-line. When a user selects a menu item, it pops the two options into the text fields. I have included some basic error handling but you may want to come up with better ways to do it. There are some drawbacks I see in using a popup menu to hold hundreds of entries, so you may want to think of using a text view or other method to make navigating that many items more pleasant.

Good luck…
j

Thanks, its all working perfectly. The only real problem I had was that I copied the on clicked thingy to a on choose menu item thingy but forgot to delete the first if that was for a button. I think you should get you name in the credits as you code is almost twice as long as the rest of the code in the app. I plan on putting something like “Major code help provided by jobu from the MacScripter fourms” unless you want me to put something else. I’ll let you know when I get the app finished, there’s still the issue of adding the 100+ default items to the data file, writing the readme with insturctions on how to edit the datafile and so on.

Oops, its only working perfectly on my computer… Its giving the no data file error on other people’s computers. I’m not sure how to fix this, I tried chaning that -4 to -3 but it still complained…

Do the other people HAVE the file on their computer? :wink: Make sure you’re spelling is correct, and that there is a colon “:” before the string you append to the path2Dir var that lists the path to the file (see comments after the hierarchy below). As I said, if you want to do it this way, you have to distribute the app in a folder, rather than standalone. Sometimes an app can be dragged by itself into the applications folder (or wherever) and it’s ok. It this case, you need to put your distribution in a folder, and the entire folder has to be installed. You must include the database file with it’s correct folder and name, and you might want to check for the file and write it and create it’s directory through the script if it’s not there. Since you want to provide a default database, you should create the whole package, and then write the code to (re-)create the file in case someone pitches it. Note the directory structure from my previous post…

/Applications
__/MyApp
____MyApp.app
____/Resources
_______MyTextFile.txt

Using this example, the part in the code where the path2Data var is created should read “:Resources:MyTextFile.txt”. If you’re using the exact code I gave you, put the “Database” file (no .txt extension) file right in the same folder as the app. As I said you might have to tweak the -4/-3 thing too, to get the right path, because it will be different depending on whether you’re running it from your build directory in PB, or if you are running it say out of the Applications folder in a deployment version. You might set up a text field in your app and set it to the value of path2Data so you can see which file the script is actually looking for(i.e. set contents of “testTextField” of window “theWIndow” to path2Data)

If you can’t figure it out, You could PM me with some specifics about where you’ve put things, what you’ve changed and kept the same, etc. Or, you could send me (jobu10000@yahoo.com) a copy of your setup (a “development” version), and I could take a look at it since I’m already “intimate” :rolleyes: with the code.

j

Yeah, I blindly misread the folder structure… all fixed now. Good idea about remaking the default file in case they accidently delete it. I’ll do that. Thanks a bunch for the help.