Implement multi-column sorting in NSTableView - objective-c

I want my NSTableView(s) to allow users to select multiple columns for sorting. I have the default sorting behavior working just fine, but I want the user to be able to click on a primary column header to establish the primary sort order, and then Shift, Option, or Command click on a secondary column header(s) to define sub-sorting.
This seems like a no-brainer, and I would have sworn that I've seen scores of apps that implement this, but hours of searching and reading Apple's documentation has found me no closer to a solution.
I suspect a solution can be implemented using the table delegate method -tableView:didClickTableColumn: (and possibly -tableView:mouseDownInHeaderOfTableColumn:). My idea is to catch this message, examine the currentEvent and, if the appropriate modifier key is being held down, undo the effects of the last -tableView:sortDescriptorsDidChange: message and reorder the sort descriptors into the desired order.
I also want the column header sort indicators to draw accordingly. I suspect that I'll need to do something about NSTableHeaderCell's -drawSortIndicatorWithFrame:inView:ascending:priority: method. What perplexes me about that one is I can find no place where the sort indicator state for a column is maintained (or at least accessible using the standard APIs). So I guess I'll have to subclass NSTableColumn or NSTableHeaderCell and provide my own state. The other thing that confuses me is that the header draw method clearly seems to support a "priority" parameter for multi-key sorting, but I can find nothing in the table column or view classes that let you specify this.
Anyway, if anyone has experience doing this I'd appreciate any feedback, suggestions, techniques, known pitfalls, etc. that you might have. (sample code would not go unappreciated)

Related

Insert items into alphabetical sections in tableview

So, I have an array of various names and I have populated the table with section headers
A-Z.
Is it correct to find the first char of my data and then subsequently put it in the correct section, or is there a way to do it using a faster method.
I believe what I am doing is wrong as I am thinking of making an A array for example and then find every element starting with 'A' and insert it inside. But this is a bit crazy as then, I would need to create A-Z arrays which I seriously do not think that is the correct way.
I'm sorry if this is posted in the documentations but I don't seem to be able to find it.
Any help from you guys in this matter?
Well I actually did it this way, too and I don't see any reasons why this shouldn't be done, as it decouples the fetching / sorting process from refreshing the tableview, which in turn keeps loading and scrolling the tableview smooth.
Having A-Z arrays is not a big issue memorywise since they're just holding references to your data objects anyway and not the data itself. But it allows you fast access to your data objects without the need for expensive comparison operations.
Just make sure your arrays are kept up to date if data objects are added or deleted.

Distinct Row Templates for NSPredicateEditor/NSRuleEditor rows

I'm trying to figure out if it's possible to use different row templates for specific rows in an NSPredicateEditor (or, if need be, an NSRuleEditor). I've got a screenshot that I think helps me explain this more clearly.
In this contrived example, I only want people to generate a filter that looks for a specific path above a certain size. So, in Section A (the Any block), users can only specify path rules (and the users can add additional paths). In section B, I only want the Size option to be available.
Nothing's jumping out at me from the docs (or, the stuff that does jump out at me ends up being something else), but it seems like this is the sort of thing that might come in handy, which makes me think it might be possible.
From what I understand about NSPredicateEditor, this is not possible. You might be able to swing it if you do everything yourself with an NSRuleEditor, but I haven't played with that class as much.
So in a nutshell: if you implement it yourself, it's possible. With the built-in stuff, I'm 99.9% certain that it's not a configurable behavior.

How do I serialise Lambdas and Event delegates when Tombstoning on the Windows Phone 7?

I've been using the Game State Management sample which has worked so far. I've hit a snag though: when Tombstoning, the screens are serialised; the only trouble is, the MessageBoxScreen has event handlers for Accepted and Cancelled.
What's the best way to serialise these? I did a bit of research on using Expression Trees but this seemed overly complex for what I wanted to do.
How do you serialise these? Or... What alternative approach do you use to save the state of a screen that contains delegates?
I'd definitely steer clear of attempting to serialize anything remotely resembling a lambda, or for that matter, named methods. Remember: you're storing state, and nothing else.
Depending on how far and wide your various assignments to these delegates are, you might be able to get away with maintaining a Dictionary<String, WhateverDelagateType>, serializing the keys and looking up the callbacks after deserialization.
Another thing to consider--I'm no expert, but reading between the lines it sounds as if you're working towards tombstoning a very temporary modal dialog. Do you really want that? You might be better off bringing your user right to the high scores table, or whatever follows your dialog, on his/her return.
I decided against this. I instead persists game flow as a kind of 'flow chart'.
The flow chart is declared in code and has properties 'LastShape' and 'LastResultFromShape'.
In my code, I rebuild the flow chart definitions each time, something like this:
flowChart.AddShape( "ShowSplash" );
flowChart.AddLine( "MainMenu", ()=>lastResult=="Clicked" || lastResult=="TimedOut");
flowChart.AddShape( "MainMenu");
flowChart.AddLine( #"ShowOptions", ()=>lastResult=="OptionsClicked");
flowChar.AddLine( #"ShowSplash", ()=>lastResult==#"TimedOut");
etc.etc.
The flow goes from the top down, so 'AddLine' relates to the last shape added.
After tombstoning, I just read the last shape and the last result and decide where to go in the flowchart based on that.

Can i get/set the index generated by checking the 'indexed' checkbox? (core data)

I have 2 entities. entity A will hold many entity Bs and order will matter.
if i check the little box that says 'indexed' in xcode, how do i go about using that index, if i even can? ( i know that i CAN use it in some way: http://cocoawithlove.com/2008/03/testing-core-data-with-very-big.html but i am not so spiffy with Obj-c yet.)
I have seen this Indexed Relationships in Core Data , but it seems broken and too much over my head to fix myself.
Index doesn't mean what you think it means. In this context, "indexed" means like the index of a book. It add a lookup table so the database can find individual records quickly. If you need to be able to sort the records into a specific order, use NSSortDescriptor with the NSFetchRequest. If the existing properties are not what you want to sort on, you'll need to add another property.

Getting rid of hard coded values when dealing with lookup tables and related business logic

Example case:
We're building a renting service, using SQL Server. Information about items that can be rented is stored in a table. Each item has a state that can be either "Available", "Rented" or "Broken". The different states reside in a lookup table.
ItemState table:
id name
1 'Available'
2 'Rented'
3 'Broken'
Adding to this we have a business rule which states that whenever an item is returned, it's state is changed from "Rented" to "Available".
This could be done with a an update statement like "update Items set state=1 where id=#itemid". In application code we might have an enum that maps to the ItemState id:s. However, these contain hard coded values that could lead to maintenance issues later on. Say if a developer were to change the set of states but forgot to fix the related business logic layer...
What good methods or alternate designs are there for dealing with this type of design issues?
Links to related articles are also appreciated in addition to direct answers.
In my experience this is a case where you actually have to hardcode, preferably by using an Enum which integer values match the id's of your lookup tables. I can't see nothing wrong with saying that "1" is always "Available" and so forth.
Most systems that I've seen hard code the lookup table values and live with it. That's because, in practice, code tables rarely change as much as you think they might. And if they ever do change, you generally need to re-compile any programs that rely on that DDL anyway.
That said, if you want to make the code maintainable (a laudable goal), the best approach would be to externalize the values into a properties file. Then you can edit this file later without having to re-code your entire app.
The limiting factor here is that your app depends for its own internal state on the value you get from the lookup table, so that implies a certain amount of coupling.
For lookups where the app doesn't rely on that code, (for instance, if your code table stores a list of two-letter state codes for use in an address drop-down), then you can lazily load the codes into an object and access them only when needed. But that won't work for what you're doing.
When you have your lookup tables as well as enums defined in the code, then you always have an issue with keeping them in sync. There is not much that can be done here. Both live effectively in two different worlds and are generally unaware of each other.
You may wish to reject using lookup tables and only let your business logic operate these values. In that case you miss the options of relying on referential integrity to back you ap on the data integrity.
The other option is to build up your application in that way that you never need these values in your code. That means moving part of your business logic to the database layer, meaning, putting them in stored procedures and triggers. This will also have the benefit of being agnostic to the client. Anyone can invoke SPs and get assured the data will be kept in the consistence state, consistent with your business logic rules as well.
You'll need to have some predefined value that never changes, be it an integer, a string or something else.
In your case, the numerical value of the state is the state's surrogate PRIMARY KEY which should never change in a well-designed database.
If you're concerned about the consistency, use a CHAR code: A, R or B.
However, you should stick to it as well as to a numerical code so that A always means Available etc.
You database structure should be documented as well as the code is.
The answer depends entirely on the language you're using: solutions for this are not the same in Java, PHP, Smalltalk or even Assembler...
But let me tell you something: while it's true hard coded values are not a great thing, there are times in which you do need them. And this one is pretty much one of them: you need to declare in your code your current knowledge of the business logic, which includes these hard coded states.
So, in this particular case, I would hard code those values.
Don't overdesign it. Before trying to come up with a solution to this problem, you need to figure out if it's even a problem. Can you think of any legit hypothetical scenario where you would change the values in the itemState table? Not just "What if someone changes this table?" but "Someone wants to change this table in X way for Y reason, what effect would that have?". You need to stay realistic.
New state? you add a row, but it doesn't affect the existing ones.
Removing a state? You have to remove the references to it in code anyway.
Changing the id of a state? There is no legit reason to do that.
Changing the name of a state? There is no legit reason to do that.
So there really should be no reason to worry about this. But if you must have this cleanly maintainable in the case of irrational people who randomly decide to change Available to 2 because it just fits their Feng Shui better, make sure all tables are generated via a script which reads these values from a configuration file, and then make sure all code reads constants from that same configuration file. Then you have one definition location and any time you want to change the value you modify that configuration file instead of the DB/code.
I think this is a common problem and a valid concern, that's why I googled and found this article in the first place.
What about creating a public static class to hold all the lookup values, but instead of hard-coding, we initialize these values when the application is loaded and use names to refer them?
In my application, we tried this, it worked. Also you can do some checking, e.g. the number of different possible values of a lookup in code should be the same as in db, if it's not, log/email/etc. But I don't want to manually code this for the status of 40+ biz entities.
Moreover, this can be part of the bigger problem of OR mapping. We're exposed with too much details of the persistence layer, and thus we have to take care of it. With technologies like Entity Framework, we don't need to worry about the "sync" part because it's automated, am I right?
Thanks!
I've used a similar method to what you're describing - a table in the database with values and descriptions (useful for reporting, etc.) and an enum in code. I've handled the synchronization with a comment in code saying something like "these values are taken from table X in database ABC" so that the programmer knows the database needs to be updated. To prevent changes from the database side without the corresponding changes in code I set permissions on the table so that only certain people (who hopefully remember they need to change the code as well) have access.
The values have to be hard-coded, which effectively means that they can't be changed in the database, which means that storing them in the database is redundant.
Therefore, hard-code them and don't have a lookup table in the database. Instead store the items state directly in the items table.
You can structure your database so that your application doesn't actually have to care about the codes themselves, but rather the business rules behind them.
I have done both of the following:
Do one or more of your codes have a certain characteristic, such as IsAvailable, that the application cares about? If so, add it as a flag column to the code table, where those that match are set to true (or your DB's equivalent), and those that don't are set to false.
Do you need to use a specific, single code under a certain condition? You can create a singleton table, named something like EnvironmentSettings, with a column such as ItemStateIdOnReturn that's a foreign key to the ItemState table.
If I wanted to avoid declaring an enum in the application, I would use #2 to address the example in the question.
Whether you take this approach depends on your application's priorities. This type of structure comes at the cost of additional development and lookup overhead. Plus, if every individual code comes with its own business rules, then it's not practical to create one new column per required code.
But, it may be worthwhile if you don't want to worry about synchronizing your application with the contents of a code table.