Alexandre Lision | 8521baa | 2015-03-13 11:08:00 -0400 | [diff] [blame] | 1 | /* |
Alexandre Lision | 9fe374b | 2016-01-06 10:17:31 -0500 | [diff] [blame] | 2 | * Copyright (C) 2015-2016 Savoir-faire Linux Inc. |
Alexandre Lision | 8521baa | 2015-03-13 11:08:00 -0400 | [diff] [blame] | 3 | * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com> |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by |
| 7 | * the Free Software Foundation; either version 3 of the License, or |
| 8 | * (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
Alexandre Lision | 8521baa | 2015-03-13 11:08:00 -0400 | [diff] [blame] | 18 | */ |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 19 | #import "QNSTreeController.h" |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 20 | |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 21 | #import <QDebug> |
| 22 | |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 23 | @interface Node : NSObject { |
| 24 | NSMutableArray *children; |
| 25 | } |
| 26 | @end |
| 27 | |
| 28 | @implementation Node |
| 29 | - (id) init |
| 30 | { |
| 31 | if (self = [super init]) { |
| 32 | children = [[NSMutableArray alloc] init]; |
| 33 | } |
| 34 | return self; |
| 35 | } |
| 36 | |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 37 | - (void) addChild:(Node*) child AtIndex:(NSUInteger) idx |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 38 | { |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 39 | [children insertObject:child atIndex:idx]; |
| 40 | } |
| 41 | |
| 42 | - (NSMutableArray*) children |
| 43 | { |
| 44 | return children; |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 45 | } |
| 46 | |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 47 | @end |
| 48 | |
| 49 | |
| 50 | @implementation QNSTreeController |
| 51 | |
| 52 | - (id) initWithQModel:(QAbstractItemModel*) model |
| 53 | { |
Alexandre Lision | 81c9721 | 2015-06-17 15:51:53 -0400 | [diff] [blame] | 54 | self = [super init]; |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 55 | self->privateQModel = model; |
| 56 | |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 57 | NSMutableArray* nodes = [[NSMutableArray alloc] init]; |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 58 | [self populate:nodes]; |
Alexandre Lision | f5fc479 | 2015-03-17 09:15:43 -0400 | [diff] [blame] | 59 | |
Alexandre Lision | 4dfcafc | 2015-08-20 12:43:23 -0400 | [diff] [blame] | 60 | [self connect]; |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 61 | return [self initWithContent:nodes]; |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 62 | } |
| 63 | |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 64 | -(void) populate:(NSMutableArray*) nodes |
Alexandre Lision | f5fc479 | 2015-03-17 09:15:43 -0400 | [diff] [blame] | 65 | { |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 66 | for (int i = 0 ; i < self->privateQModel->rowCount() ; ++i) { |
| 67 | Node* n = [[Node alloc] init]; |
| 68 | //qDebug() << "POUPL TOP:"<< self->privateQModel->index(i, 0) ; |
| 69 | [self populateChild:[n children] withParent:self->privateQModel->index(i, 0)]; |
| 70 | [nodes insertObject:n atIndex:i]; |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | - (void) populateChild:(NSMutableArray*) nodes withParent:(QModelIndex)qIdx |
| 75 | { |
| 76 | if (!qIdx.isValid()) |
| 77 | return; |
| 78 | for (int i = 0 ; i < self->privateQModel->rowCount(qIdx) ; ++i) { |
| 79 | Node* n = [[Node alloc] init]; |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 80 | [self populateChild:[n children] withParent:self->privateQModel->index(i, 0, qIdx)]; |
| 81 | [nodes insertObject:n atIndex:i]; |
Alexandre Lision | f5fc479 | 2015-03-17 09:15:43 -0400 | [diff] [blame] | 82 | } |
| 83 | } |
| 84 | |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 85 | - (BOOL)isEditable |
| 86 | { |
| 87 | return self->privateQModel->flags(self->privateQModel->index(0, 0)) | Qt::ItemIsEditable; |
| 88 | } |
| 89 | |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 90 | - (QModelIndex) indexPathtoQIdx:(NSIndexPath*) path |
Alexandre Lision | f5fc479 | 2015-03-17 09:15:43 -0400 | [diff] [blame] | 91 | { |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 92 | NSUInteger myArray[[path length]]; |
| 93 | [path getIndexes:myArray]; |
Alexandre Lision | f5fc479 | 2015-03-17 09:15:43 -0400 | [diff] [blame] | 94 | QModelIndex toReturn; |
Alexandre Lision | 3b0bd33 | 2015-03-15 18:43:07 -0400 | [diff] [blame] | 95 | |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 96 | for (int i = 0; i < path.length; ++i) { |
Alexandre Lision | 3b0bd33 | 2015-03-15 18:43:07 -0400 | [diff] [blame] | 97 | toReturn = self->privateQModel->index(myArray[i], 0, toReturn); |
| 98 | } |
| 99 | |
Alexandre Lision | f5fc479 | 2015-03-17 09:15:43 -0400 | [diff] [blame] | 100 | return toReturn; |
| 101 | } |
| 102 | |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 103 | - (QModelIndex) toQIdx:(NSTreeNode*) node |
Alexandre Lision | 3b0bd33 | 2015-03-15 18:43:07 -0400 | [diff] [blame] | 104 | { |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 105 | return [self indexPathtoQIdx:node.indexPath]; |
| 106 | } |
Alexandre Lision | 3b0bd33 | 2015-03-15 18:43:07 -0400 | [diff] [blame] | 107 | |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 108 | - (NSIndexPath*) qIdxToNSIndexPath:(QModelIndex) qIdx |
| 109 | { |
Alexandre Lision | 3b0bd33 | 2015-03-15 18:43:07 -0400 | [diff] [blame] | 110 | QModelIndex tmp = qIdx.parent(); |
| 111 | NSMutableArray* allIndexes = [NSMutableArray array]; |
| 112 | while (tmp.isValid()) { |
| 113 | [allIndexes insertObject:@(tmp.row()) atIndex:0]; |
| 114 | tmp = tmp.parent(); |
| 115 | } |
| 116 | [allIndexes insertObject:@(qIdx.row()) atIndex:allIndexes.count]; |
| 117 | |
| 118 | NSUInteger indexes[allIndexes.count]; |
| 119 | for (int i = 0 ; i < allIndexes.count ; ++i) { |
| 120 | indexes[i] = [[allIndexes objectAtIndex:i] intValue]; |
| 121 | } |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 122 | return [[NSIndexPath alloc] initWithIndexes:indexes length:allIndexes.count]; |
| 123 | } |
| 124 | |
| 125 | - (void) insertNodeAtQIndex:(QModelIndex) qIdx |
| 126 | { |
| 127 | NSIndexPath* path = [self qIdxToNSIndexPath:qIdx]; |
| 128 | //qDebug() << "insertNodeAt" << qIdx; |
| 129 | //NSLog(@"insertNodeAt index: %@", path); |
| 130 | if (path.length == 1 && [path indexAtPosition:0] <= [[self arrangedObjects] count]) |
| 131 | [self insertObject:[[Node alloc] init] atArrangedObjectIndexPath:path]; |
| 132 | else if (path.length > 1) |
| 133 | [self insertObject:[[Node alloc] init] atArrangedObjectIndexPath:path]; |
| 134 | } |
| 135 | |
| 136 | - (void) removeNodeAtQIndex:(QModelIndex) qIdx |
| 137 | { |
| 138 | NSIndexPath* path = [self qIdxToNSIndexPath:qIdx]; |
| 139 | if ([self.arrangedObjects descendantNodeAtIndexPath:path]) { |
| 140 | //NSLog(@"removeNodeAt index: %@", path); |
| 141 | [self removeObjectAtArrangedObjectIndexPath:path]; |
| 142 | } |
Alexandre Lision | 3b0bd33 | 2015-03-15 18:43:07 -0400 | [diff] [blame] | 143 | } |
| 144 | |
Alexandre Lision | 89edc6a | 2015-11-09 11:30:47 -0500 | [diff] [blame] | 145 | - (void) setSelectionQModelIndex:(QModelIndex) qIdx |
| 146 | { |
| 147 | NSIndexPath* path = [self qIdxToNSIndexPath:qIdx]; |
| 148 | [self setSelectionIndexPath:path]; |
| 149 | } |
| 150 | |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 151 | - (void)connect |
| 152 | { |
| 153 | QObject::connect(self->privateQModel, |
| 154 | &QAbstractItemModel::rowsInserted, |
| 155 | [=](const QModelIndex & parent, int first, int last) { |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 156 | for( int row = first; row <= last; ++row) { |
| 157 | //qDebug() << "INSERTING:"<< self->privateQModel->index(row, 0, parent) ; |
| 158 | if(!self->privateQModel->index(row, 0, parent).isValid()) |
| 159 | continue; |
| 160 | |
| 161 | [self insertNodeAtQIndex:self->privateQModel->index(row, 0, parent)]; |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 162 | } |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 163 | }); |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 164 | |
| 165 | QObject::connect(self->privateQModel, |
| 166 | &QAbstractItemModel::rowsAboutToBeMoved, |
| 167 | [=](const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow) { |
Alexandre Lision | 4dfcafc | 2015-08-20 12:43:23 -0400 | [diff] [blame] | 168 | //NSLog(@"rows about to be moved, start: %d, end: %d, moved to: %d", sourceStart, sourceEnd, destinationRow); |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 169 | /* first remove the row from old location |
| 170 | * then insert them at the new location on the "rowsMoved signal */ |
| 171 | for( int row = sourceStart; row <= sourceEnd; row++) { |
| 172 | //TODO |
| 173 | } |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 174 | }); |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 175 | |
| 176 | QObject::connect(self->privateQModel, |
| 177 | &QAbstractItemModel::rowsMoved, |
Alexandre Lision | 4dfcafc | 2015-08-20 12:43:23 -0400 | [diff] [blame] | 178 | [self](const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow) { |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 179 | for( int row = sourceStart; row <= sourceEnd; row++) { |
Alexandre Lision | bfa68f6 | 2015-09-10 08:38:42 -0400 | [diff] [blame] | 180 | NSIndexPath* srcPath = [self qIdxToNSIndexPath:self->privateQModel->index(row, 0, sourceParent)]; |
Alexandre Lision | 4dfcafc | 2015-08-20 12:43:23 -0400 | [diff] [blame] | 181 | NSIndexPath* destPath = [self qIdxToNSIndexPath:self->privateQModel->index(destinationRow, 0, destinationParent)]; |
| 182 | |
| 183 | [self moveNode:[self.arrangedObjects descendantNodeAtIndexPath:srcPath] toIndexPath:destPath]; |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 184 | } |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 185 | }); |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 186 | |
| 187 | QObject::connect(self->privateQModel, |
| 188 | &QAbstractItemModel::rowsAboutToBeRemoved, |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 189 | [self](const QModelIndex & parent, int first, int last) { |
Alexandre Lision | 21666f3 | 2015-09-22 17:04:36 -0400 | [diff] [blame] | 190 | for( int row = last; row >= first; --row) { |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 191 | //qDebug() << "REMOVING:"<< self->privateQModel->index(row, 0, parent) ; |
| 192 | if (!self->privateQModel->index(row, 0, parent).isValid()) |
| 193 | continue; |
| 194 | |
| 195 | [self removeNodeAtQIndex:self->privateQModel->index(row, 0, parent)]; |
| 196 | } |
| 197 | }); |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 198 | |
| 199 | QObject::connect(self->privateQModel, |
| 200 | &QAbstractItemModel::rowsRemoved, |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 201 | [self](const QModelIndex& parent, int first, int last) { |
| 202 | |
| 203 | }); |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 204 | |
| 205 | QObject::connect(self->privateQModel, |
| 206 | &QAbstractItemModel::layoutChanged, |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 207 | [self]() { |
Alexandre Lision | f5b90da | 2015-03-20 18:13:54 -0400 | [diff] [blame] | 208 | //NSLog(@"layout changed"); |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 209 | [self rearrangeObjects]; |
| 210 | }); |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 211 | |
Alexandre Lision | ee09846 | 2015-10-22 17:22:50 -0400 | [diff] [blame] | 212 | /* No way to 'update' a row, only insert/remove/move |
Alexandre Lision | f5fc479 | 2015-03-17 09:15:43 -0400 | [diff] [blame] | 213 | QObject::connect(self->privateQModel, |
| 214 | &QAbstractItemModel::dataChanged, |
Alexandre Lision | 2db8f47 | 2015-07-22 15:05:46 -0400 | [diff] [blame] | 215 | [self](const QModelIndex &topLeft, const QModelIndex &bottomRight) { |
Alexandre Lision | f5fc479 | 2015-03-17 09:15:43 -0400 | [diff] [blame] | 216 | }); |
Alexandre Lision | ee09846 | 2015-10-22 17:22:50 -0400 | [diff] [blame] | 217 | */ |
Alexandre Lision | 5855b6a | 2015-02-03 11:31:05 -0500 | [diff] [blame] | 218 | } |
| 219 | |
| 220 | @end |