How to use IKImagebrowserView's group display? - grouping

The effect I want is like the iPhoto group(or timeline) displaying.
I have already realized the common IKImageBrowserView. which is like
But I don't know how to assign them in different groups.
I referred: customizing IKImageBrowserView group appearance, which is the only post in stackoverflow, maybe.
I used the 4 methods of IKImageBrowserDataSource.
- (NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView *)browser;
- (id)imageBrowser:(IKImageBrowserView *)browser itemAtIndex:(NSUInteger)index;
- (NSUInteger)numberOfGroupsInImageBrowser:(IKImageBrowserView *)browser;
- (NSDictionary *)imageBrowser:(IKImageBrowserView *)browser groupAtIndex:(NSUInteger)index;
I think I don't know how to write code for the last 2 methods.

You definitely need to implement those last two methods for groups to appear. If you simply want to see the effect, you can do something like this:
- (NSUInteger) numberOfGroupsInImageBrowser:(IKImageBrowserView *) aBrowser
{
return 1;
}
- (NSDictionary *) imageBrowser:(IKImageBrowserView *) aBrowser groupAtIndex:(NSUInteger) index
{
NSRange r = {0, 3};
return #{IKImageBrowserGroupRangeKey: [NSValue valueWithRange:r],
IKImageBrowserGroupBackgroundColorKey: [NSColor redColor],
IKImageBrowserGroupStyleKey: [NSNumber numberWithInt:IKGroupDisclosureStyle]};
}
The important key in the directory returned by groupAtIndex is IKImageBrowserGroupRangeKey. This describes what range of images are in a given group. Note that NSRange is a structure and is not derived from NSObject so it can't be used as a value in a dictionary. Hence, it must be converted to an NSValue.
For this to be truly useful you'll want to cache your set of range values and provide a mechanism for grouping and ungrouping images, but I hope this is enough to get you started

Related

Add empty option to List Validator

I'm trying to add the option to my users that, on a List Validator, to allow select any of the options or a blank option. Spreadjs has the IgnoreBlanks setting, which I use, so when the user uses the delete key or the backspace and deletes the cell it validates correctly.
However, I would love to use the same functionality as in Excel, which allows blank options in the list validator, in part of the list.
I've tried to target the <select> element that holds the list and programmatically add the empty element, however, it crashes after the user selects the empty option.
I've also tried to add different escaped characters to the list. If I select a character that represents an empty string or a tab, it won't add a new option to the list. If I use any strange character, or even the null character \0 you get a new option to select, but the content is that typical rectangle you see when your font doesn't have the character you're trying to display.
I've also tested using a regular ListValidator like in the example pages, not our custom functionality and doesn't work either.
https://www.grapecity.com/demos/spread/JS/TutorialSample/#/demos/basicDataValidator
I have also tried creating a FormulaListValidator, and if my range has empty cells I could then get an empty option on my list, however, because the range may have duplicates, I get duplicated options.
After researching a little bit I found a workaround in a different language which I adapted to Typescript (Angular 6)
export const getListValidatorFromArray = (spread: GC.Spread.Sheets.Workbook, data: any[]) => {
// saving validation list values in a hidden sheet
spread.addSheet(spread.getSheetCount());
const sheet = spread.getSheet(spread.getSheetCount() - 1);
sheet.visible(false);
for (let i = 0; i < data.length; i++) {
sheet.setValue(i, 0, data[i]);
}
// create validator based on the values
const dv = GC.Spread.Sheets.DataValidation.createFormulaListValidator(
'=' + sheet.name() + '!$A$1:' + sheet.name() + '!$A$' + data.length
);
return dv;
};
Note: This creates an extra sheet for each validator you create. Makes sure you reuse them as much as possible (i.e. assigning it to a variable when it's created, and reusing the variable for other columns/rows that use the same one).

CouchDB View - filter keys before grouping

I have a CouchDB database which has documents with the following format:
{ createdBy: 'userId', at: 123456, type: 'action_type' }
I want to write a view that will give me how many actions of each type were created by which user. I was able to do that creating a view that does this:
emit([doc.createdBy, doc.type, doc.at], 1);
With the reduce function "sum" and consuming the view in this way:
/_design/userActionsDoc/_view/userActions?group_level=2
this returns a result with rows just in the way I want:
"rows":[ {"key":["userId","ACTION_1"],"value":20}, ...
the problem is that now I want to filter the results for a given time period. So I want to have the exact same information but only considering actions which happened within a given time period.
I can filter the documents by "at" if I emit the fields in a different order.
?group_level=3&startkey=[149328316160]&endkey=[1493283161647,{},{}]
emit([doc.at, doc.type, doc.createdBy], 1);
but then I won't get the results grouped by userId and actionType. Is there a way to have both? Maybe writing my own reduce function?
I feel your pain. I have done two different things in the past to attempt to solve similar issues.
The first pattern is a pain and may work great or may not work at all. I've experienced both. Your map function looks something like this:
function(doc) {
var obj = {};
obj[doc.createdBy] = {};
obj[doc.createdBy][doc.type] = 1;
emit(doc.at, obj);
// Ignore this for now
// emit(doc.at, JSON.stringify(obj));
}
Then your reduce function looks like this:
function(key, values, rereduce) {
var output = {};
values.forEach(function(v) {
// Ignore this for now
// v = JSON.parse(v);
for (var user in v) {
for (var action in v[user]) {
output[user][action] = (output[user][action] || 0) + v[user][action];
}
}
});
return output;
// Ignore this for now
// return JSON.stringify(output);
}
With large datasets, this usually results in a couch error stating that your reduce function is not shrinking fast enough. In that case, you may be able to stringify/parse the objects as shown in the "ignore" comments in the code.
The reasoning behind this is that couchdb ultimately wants you to output a simple object like a string or integer in a reduce function. In my experience, it doesn't seem to matter that the string gets longer, as long as it remains a string. If you output an object, at some point the function errors because you have added too many props to that object.
The second pattern is potentially better, but requires that your time periods are "defined" ahead of time. If your time period requirements can be locked down to a specific year, specific month, day, quarter, etc. You just emit multiple times in your map function. Below I assume the at property is epoch milliseconds, or at least something that the date constructor can accurately parse.
function(doc) {
var time_key;
var my_date = new Date(doc.at);
//// Used for filtering results in a given year
//// e.g. startkey=["2017"]&endkey=["2017",{}]
time_key = my_date.toISOString().substr(0,4);
emit([time_key, doc.createdBy, doc.type], 1);
//// Used for filtering results in a given month
//// e.g. startkey=["2017-01"]&endkey=["2017-01",{}]
time_key = my_date.toISOString().substr(0,7);
emit([time_key, doc.createdBy, doc.type], 1);
//// Used for filtering results in a given quarter
//// e.g. startkey=["2017Q1"]&endkey=["2017Q1",{}]
time_key = my_date.toISOString().substr(0,4) + 'Q' + Math.floor(my_date.getMonth()/3).toString();
emit([time_key, doc.createdBy, doc.type], 1);
}
Then, your reduce function is the same as in your original. Essentially you're just trying to define a constant value for the first item in your key that corresponds to a defined time period. Works well for business reporting, but not so much for allowing for flexible time periods.

Count vs len on a Django QuerySet when some results are filtered

A more general version of my question has already beek asked: Count vs len on a Django QuerySet
My case is a bit different, though. It starts with something like this:
messages = Message.objects.filter(foo=bar)
To get error_message_count and other_message_count, which is better?
error_message_count = len(message for message in messages if message.is_error)
other_message_count = len(messages) - error_message_count
or:
error_message_count = messages.filter(is_error = True).count()
other_message_count = messages.count() - error_message_count
or even:
error_message_count = messages.filter(is_error = True).count()
other_message_count = messages.filter(is_error = False).count()
I suspect that the first solution boils down to only one query, and the others in two. But perhaps Django and/or the DBMS make one of the second two more efficient?
I'll accept 'profile it' as an answer, but I wonder if any of these solutions are considered best practice.
As far as I know, if you retrieve all of the objects and check one by one for a boolean, it is not good way because you do it by using python which uses memory.
On the other hand, 'count' is executed in database and you don't have to get all of the rows for just checking one boolean. Therefore, I think good way is the middle one.
error_message_count = messages.filter(is_error = True).count()
other_message_count = messages.count() - error_message_count
Also, when you defined 'messages', it is a queryset but it is not executed in db until you need it which uses lazy evaluation. So, If you use a for loop for that queryset, it'll execute it directly. But if you add another filter for the desired boolean, It'll only update the database query. That's why it's better for performance.
To decide between these :
error_message_count = len(message for message in messages if message.is_error)
other_message_count = len(messages) - error_message_count
or:
error_message_count = messages.filter(is_error = True).count()
other_message_count = messages.count() - error_message_count
there are some important factors that need to be considered i.e. do you have an index on is_error, what's the size of messages table and how many +ve / -ve matches do you expect. Unfortunately, profile-it will indeed give you a clear picture. If your table size is small (e.g. few thousand entries, it doesn't matter). If it's of the order of millions of entries, it should be fairly easy to get a clear picture with a profile.

Sencha Touch 2 list background change

I have a list within my application, but was wondering if it is possible to have each list displayed show a different background colour, rather than the same one through out each item?
I have created a template but would be nice to have the background of each change colour.
Thanks
EDIT: I have also created the same list via a 'Ext.dataview.component.DataItem' / 'DataView' so if this is easier to control separately then great, as I am looking at interfering in te process of creating each and setting its background, if that is at all possible.
You could try to do that with simply XTemplate:
var tpl = new Ext.XTemplate(
'<p>Name: {name}</p>',
'<p>Company: {[values.company.toUpperCase() + ", " + values.title]}</p>',
'<p>Kids: ',
'<tpl for="kids">',
'<div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
'{name}',
'</div>',
'</tpl></p>'
);
take a look at their explanations, might find something interesting:
http://docs.sencha.com/touch/2-0/#!/api/Ext.XTemplate
I have seen many variants on the Ext.query('class').up().addCls('backgroundClass'); hack, which makes perfect sense to me, but my question is WHEN are people calling this? I can't put it in 'painted', since DOM doesn't seem to exist yet.. where/when are you guys executing the Ext.get(..) call?
I have been looking for this also, and I had a hard time finding out how to access the individual items of a xlist...
This is the way I finally did it:
in your itemTpl, add a class to your < div >, using the property 'id' of your model:
itemTpl:'< div class="my_list_item_{id}"> ... content ... < /div>'
the tricky part is that if you want to set the background color of the whole item area, you have to access to < div > with class 'x-item-label' that is wrapping your itemTpl < div >.
Here is how I did it (for the first item as an example):
Ext.select('.my_list_item_1').first().up('div.x-list-item-label').addCls('background_item');
where 'background_item' is a CSS style, defining your background color.
(Since there is no way (at least that I know of) to get the index count of your items in the 'itemTpl' config, I had to use to automatic 'id' property of my model/store.
Note that if you apply filtering/sorting/... on your store, this property will not be sorted anymore. So if you want to link the order displayed in your list to the 'id' property, you have to do something like 'Ext.StoreManager.get('MyStore').getAt(indexInList).get('id') )
Hope this helps...
Since Sencha Touch 2.2.1 it's also possible to use striped parameter (more info here). It will add x-list-item-odd class to odd items of your list.

Django queryset to match all related objects

Let's say I have a ForeignKey from Coconut to Swallow (ie, a swallow has carried many coconuts, but each coconut has been carried by only one swallow). Now let's say that I have a ForeignKey from husk_segment to Coconut.
Now, I have a list of husk_segments and I want to find out if ALL of these have been carried gripped by a particular swallow.
I can have swallow.objects.filter(coconuts_carried__husk_sements__in = husk_segment_list) to show that this swallow has gripped at least one husk segment in the list. Now, how can I show that every husk segment that the swallow has ever carried are in this list?
I can have swallow.objects.filter(coconuts_carried__husk_sements__in =
husk_segment_list) to show that this swallow has gripped at least one
husk segment in the list.
No, this is wrong, this gives you a list of swallows which have carried at least one husk segment from *husk_segment_list*.
If I've understood right, we are talking about checking for a specific swallow.
So, from your description I guess your models look something like this:
class Swallow(models.Model):
name = models.CharField(max_length=100)
class Coconut(models.Model):
swallow = models.ForeignKey(Swallow, related_name='coconuts_carried')
class HuskSegment(models.Model):
coconut = models.ForeignKey(Coconut, related_name='husk_segments')
If you already have the husk segment list you need to check againts the swallows segments, there's no reason you need to resolve it in a query. Get the swallows' segments and check if it's a superset of your husk segment list.
So we have:
#husk_segment_list = [<object: HuskSegment>, <object: HuskSegment>, <object: HuskSegment>...]
husk_segments_set = set((husk.pk for husk in husk_segment_list))
whitey = Swallow.object.get(name='Neochelidon tibialis')
wh_segments_set = set((value[0] for value in HuskSegment.objects.filter(coconut__in=whitey.coconuts_carried.all()).values_list('id')))
whitey_has_carried_all = wh_segments_set.issuperset(husk_segments_set)
See the docs on queries spanning multi-valued relationships -- you should chain filter calls.
A simple way to go would be something like
queryset = Swallow.objects.all()
for coconut in coconuts:
queryset = queryset.filter(coconuts_carried=coconut)
A fancy way to do this in one line using reduce would be
reduce(lambda q, c: q.filter(coconuts_carried=c), coconuts, Swallow.objects.all())
If i understood your altered question correctly you should be able to compare the coconut_carried_set of the swallow with the list of coconuts that have been carried.
see docs
I'm not entirely sure that this is what you want - I guess it depends on if you know which swallow you want to check beforehand or if you want to check it against all swallows - in that case there may be a better solution.