Commit 5855b6a1 authored by Alexandre Lision's avatar Alexandre Lision

Switch to native frameworks

We now build a Cocoa application built on LibRingClient.
Qt bindings are working (need stabilization)

Refs #64818
parent 392ee727
#import <AppKit/NSApplication.h> // NSApplicationDelegate
#import "RingWindowController.h"
#import "PreferencesWindowController.h"
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property RingWindowController* ringWindowController;
@property PreferencesWindowController* preferencesWindowController;
+ (void)restoreWindowWithIdentifier:(NSString *)identifier
state:(NSCoder *)state
completionHandler:(void (^)(NSWindow *, NSError *))completionHandler;
@end
#import "AppDelegate.h"
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.ringWindowController = [[RingWindowController alloc] initWithWindowNibName:@"RingWindow"];
[self.ringWindowController showWindow:nil];
}
- (PreferencesWindowController *)preferencesWindowController
{
if (!_preferencesWindowController)
{
NSLog(@"Coucou");
_preferencesWindowController = [[PreferencesWindowController alloc] initWithWindowNibName:@"PreferencesWindow"];
_preferencesWindowController.window.restorable = YES;
_preferencesWindowController.window.restorationClass = [self class];
_preferencesWindowController.window.identifier = @"preferences";
}
return _preferencesWindowController;
}
- (IBAction)launchPreferencesWindow:(id)sender {
[[self preferencesWindowController] showWindow:nil];
}
+ (void)restoreWindowWithIdentifier:(NSString *)identifier
state:(NSCoder *)state
completionHandler:(void (^)(NSWindow *, NSError *))completionHandler
{
NSLog(@"restoreWindowWithIdentifier: %@", identifier);
NSWindow *window = nil;
if ([identifier isEqualToString:@"preferences"])
{
AppDelegate *appDelegate = [NSApp delegate];
window = [[appDelegate preferencesWindowController] window];
}
completionHandler(window, nil);
}
@end
......@@ -7,20 +7,15 @@ ENDIF(POLICY CMP0022)
SET(PROJ_NAME Ring)
SET(RING_VERSION 1.0)
PROJECT(${PROJ_NAME})
ADD_DEFINITIONS("-std=c++11")
ADD_DEFINITIONS("-std=c++0x")
PROJECT(${PROJ_NAME})
FIND_PACKAGE(Qt5Core REQUIRED)
FIND_PACKAGE(Qt5Gui REQUIRED)
FIND_PACKAGE(Qt5Widgets REQUIRED)
FIND_PACKAGE(LibRingClient REQUIRED)
# Instruct CMake to run moc automatically when needed.
SET(CMAKE_AUTOMOC ON)
INCLUDE_DIRECTORIES(SYSTEM ${Qt5Core_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(SYSTEM ${Qt5Gui_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR})
INCLUDE_DIRECTORIES(${LIB_RING_CLIENT_INCLUDE_DIR})
......@@ -30,20 +25,28 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
#Files to compile
SET(ringclient_SRCS
main.cpp
mainwindow.cpp
minimalhistorybackend.cpp
mysearchbar.cpp)
main.mm
AppDelegate.mm
RingWindowController.mm
ConversationsViewController.mm
PreferencesWindowController.mm
QNSTreeController.mm
HistoryViewController.mm
MinimalHistoryBackend.cpp)
SET(ringclient_FORMS
mainwindow.ui)
QT5_WRAP_UI(ringclient_FORMS_HEADERS ${ringclient_FORMS})
MainMenu.xib
RingWindow.xib
PreferencesWindow.xib)
SET(ringclient_HDRS
mainwindox.h
minimalhistorybackend.h
mysearchbar.h)
AppDelegate.h
RingWindowController.h
ConversationsViewController.h
PreferencesWindowController.h
HistoryViewController.h
QNSTreeController.h
MinimalHistoryBackend.h)
# Icons
......@@ -64,25 +67,29 @@ ${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_new_email.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_search.png
${CMAKE_CURRENT_SOURCE_DIR}/data/dark/ic_action_video.png)
SET_SOURCE_FILES_PROPERTIES(${ring_ICONS} PROPERTIES
MACOSX_PACKAGE_LOCATION "Resources")
MACOSX_PACKAGE_LOCATION Resources)
qt5_add_resources(rcc_files ${CMAKE_CURRENT_SOURCE_DIR}/data.qrc)
SET_SOURCE_FILES_PROPERTIES(${ringclient_FORMS} PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)
ADD_EXECUTABLE(${PROJ_NAME} MACOSX_BUNDLE
${ringclient_SRCS}
${ringclient_HEADERS_MOC}
${ringclient_FORMS_HEADERS}
${ringclient_HDRS}
${ringclient_FORMS}
${myApp_ICON}
${ring_ICONS}
${rcc_files})
${ring_ICONS})
MESSAGE("Hello" ${Qt5Core_LIBRARIES})
TARGET_LINK_LIBRARIES( ${PROJ_NAME}
${LIB_RING_CLIENT_LIBRARY}
${QT_QTCORE_LIBRARY}
${Qt5Core_LIBRARIES}
${Qt5Widgets_LIBRARIES}
${QT_QTGUI_LIBRARY}
)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AppKit")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Cocoa")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AddressBook")
SET_TARGET_PROPERTIES(${PROJ_NAME} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/cmake/MacOSXBundleInfo.plist.in
......
//
// ConversationsViewController.h
// Ring
//
// Created by Alexandre Lision on 2015-02-02.
//
//
#import <Cocoa/Cocoa.h>
#import "QNSTreeController.h"
@interface ConversationsViewController : NSViewController <NSOutlineViewDelegate> {
NSOutlineView *conversationsView;
}
@property QNSTreeController *treeController;
@property (assign) IBOutlet NSOutlineView *conversationsView;
@end
//
// ConversationsViewController.m
// Ring
//
// Created by Alexandre Lision on 2015-02-02.
//
//
#import "ConversationsViewController.h"
#import <callmodel.h>
#define COLUMNID_CONVERSATIONS @"ConversationsColumn" // the single column name in our outline view
@interface ConversationsViewController ()
@end
@implementation ConversationsViewController
@synthesize conversationsView;
@synthesize treeController;
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
NSLog(@"INIT Conversations VC");
}
return self;
}
- (void)awakeFromNib
{
NSLog(@"awakeFromNib");
treeController = [[QNSTreeController alloc] initWithQModel:CallModel::instance()];
[treeController setAvoidsEmptySelection:NO];
[treeController setChildrenKeyPath:@"children"];
[self.conversationsView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
[self.conversationsView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
[self.conversationsView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
NSInteger idx = [conversationsView columnWithIdentifier:COLUMNID_CONVERSATIONS];
[[[[self.conversationsView tableColumns] objectAtIndex:idx] headerCell] setStringValue:@"Conversations"];
}
#pragma mark - NSOutlineViewDelegate methods
// -------------------------------------------------------------------------------
// shouldSelectItem:item
// -------------------------------------------------------------------------------
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
{
return YES;
}
// -------------------------------------------------------------------------------
// dataCellForTableColumn:tableColumn:item
// -------------------------------------------------------------------------------
- (NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
NSCell *returnCell = [tableColumn dataCell];
if(item == nil)
return returnCell;
if ([[tableColumn identifier] isEqualToString:COLUMNID_CONVERSATIONS])
{
NSIndexPath* idx = ((NSTreeNode*)item).indexPath;
NSUInteger myArray[[idx length]];
[idx getIndexes:myArray];
NSLog(@"dataCellForTableColumn, indexPath: %lu", (unsigned long)myArray[0]);
QModelIndex qIdx = CallModel::instance()->index(myArray[0], 0);
QVariant test = CallModel::instance()->data(qIdx, Qt::DisplayRole);
}
return returnCell;
}
// -------------------------------------------------------------------------------
// textShouldEndEditing:fieldEditor
// -------------------------------------------------------------------------------
- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor
{
if ([[fieldEditor string] length] == 0)
{
// don't allow empty node names
return NO;
}
else
{
return YES;
}
}
// -------------------------------------------------------------------------------
// shouldEditTableColumn:tableColumn:item
//
// Decide to allow the edit of the given outline view "item".
// -------------------------------------------------------------------------------
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
return NO;
}
// -------------------------------------------------------------------------------
// outlineView:willDisplayCell:forTableColumn:item
// -------------------------------------------------------------------------------
- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
if ([[tableColumn identifier] isEqualToString:COLUMNID_CONVERSATIONS])
{
NSIndexPath* idx = ((NSTreeNode*)item).indexPath;
NSUInteger myArray[[idx length]];
[idx getIndexes:myArray];
NSLog(@"array:%@", idx);
QModelIndex qIdx;
if(idx.length == 2)
qIdx = CallModel::instance()->index(myArray[1], 0, CallModel::instance()->index(myArray[0], 0));
else
qIdx = CallModel::instance()->index(myArray[0], 0);
if(qIdx.isValid())
cell.title = CallModel::instance()->data(qIdx, Qt::DisplayRole).toString().toNSString();
}
}
// -------------------------------------------------------------------------------
// outlineViewSelectionDidChange:notification
// -------------------------------------------------------------------------------
- (void)outlineViewSelectionDidChange:(NSNotification *)notification
{
// ask the tree controller for the current selection
NSLog(@"outlineViewSelectionDidChange!!");
}
@end
//
// HistoryViewController.h
// Ring
//
// Created by Alexandre Lision on 2015-01-28.
//
//
#import <Cocoa/Cocoa.h>
#import "QNSTreeController.h"
@interface HistoryViewController : NSViewController <NSOutlineViewDelegate> {
NSOutlineView *historyView;
}
@property NSTreeController *treeController;
@property (assign) IBOutlet NSOutlineView *historyView;
@end
//
// HistoryViewController.m
// Ring
//
// Created by Alexandre Lision on 2015-01-28.
//
//
#import "HistoryViewController.h"
#import "MinimalHistoryBackend.h"
#import <historymodel.h>
#define COLUMNID_HISTORY @"HistoryColumn" // the single column name in our outline view
@implementation HistoryViewController
@synthesize treeController;
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
NSLog(@"INIT HVC");
}
return self;
}
- (void)awakeFromNib
{
NSLog(@"awakeFromNib");
treeController = [[QNSTreeController alloc] initWithQModel:HistoryModel::instance()];
[treeController setAvoidsEmptySelection:NO];
[treeController setChildrenKeyPath:@"children"];
[self.historyView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
[self.historyView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
[self.historyView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
NSInteger idx = [historyView columnWithIdentifier:COLUMNID_HISTORY];
[[[[self.historyView tableColumns] objectAtIndex:idx] headerCell] setStringValue:@"Name"];
HistoryModel::instance()->addBackend(new MinimalHistoryBackend(nil),
LoadOptions::FORCE_ENABLED);
}
#pragma mark - NSOutlineViewDelegate methods
// -------------------------------------------------------------------------------
// shouldSelectItem:item
// -------------------------------------------------------------------------------
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
{
return YES;
}
// -------------------------------------------------------------------------------
// dataCellForTableColumn:tableColumn:item
// -------------------------------------------------------------------------------
- (NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
NSCell *returnCell = [tableColumn dataCell];
if(item == nil)
return returnCell;
if ([[tableColumn identifier] isEqualToString:COLUMNID_HISTORY])
{
NSIndexPath* idx = ((NSTreeNode*)item).indexPath;
NSUInteger myArray[[idx length]];
[idx getIndexes:myArray];
//NSLog(@"dataCellForTableColumn, indexPath: %d", myArray[0]);
QModelIndex qIdx = HistoryModel::instance()->index(myArray[0], 0);
QVariant test = HistoryModel::instance()->data(qIdx, Qt::DisplayRole);
}
return returnCell;
}
// -------------------------------------------------------------------------------
// textShouldEndEditing:fieldEditor
// -------------------------------------------------------------------------------
- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor
{
if ([[fieldEditor string] length] == 0)
{
// don't allow empty node names
return NO;
}
else
{
return YES;
}
}
// -------------------------------------------------------------------------------
// shouldEditTableColumn:tableColumn:item
//
// Decide to allow the edit of the given outline view "item".
// -------------------------------------------------------------------------------
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
return NO;
}
// -------------------------------------------------------------------------------
// outlineView:willDisplayCell:forTableColumn:item
// -------------------------------------------------------------------------------
- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
if ([[tableColumn identifier] isEqualToString:COLUMNID_HISTORY])
{
NSIndexPath* idx = ((NSTreeNode*)item).indexPath;
NSUInteger myArray[[idx length]];
[idx getIndexes:myArray];
//NSLog(@"array:%@", idx);
QModelIndex qIdx;
if(idx.length == 2)
qIdx = HistoryModel::instance()->index(myArray[1], 0, HistoryModel::instance()->index(myArray[0], 0));
else
qIdx = HistoryModel::instance()->index(myArray[0], 0);
if(qIdx.isValid())
cell.title = HistoryModel::instance()->data(qIdx, Qt::DisplayRole).toString().toNSString();
}
}
// -------------------------------------------------------------------------------
// outlineViewSelectionDidChange:notification
// -------------------------------------------------------------------------------
- (void)outlineViewSelectionDidChange:(NSNotification *)notification
{
// ask the tree controller for the current selection
//NSLog(@"outlineViewSelectionDidChange!!");
}
@end
This source diff could not be displayed because it is too large. You can view the blob instead.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6254" systemVersion="13F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6254"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner"/>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="529" height="361"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1050"/>
<view key="contentView" identifier="preferences" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="529" height="361"/>
<autoresizingMask key="autoresizingMask"/>
</view>
<toolbar key="toolbar" implicitIdentifier="CF45A262-676F-4F7B-8607-AE007CC9BD32" autosavesConfiguration="NO" displayMode="iconAndLabel" sizeMode="regular" id="rLh-7J-Daz">
<allowedToolbarItems>
<toolbarItem implicitItemIdentifier="NSToolbarShowColorsItem" id="m2m-v6-Cr4"/>
<toolbarItem implicitItemIdentifier="NSToolbarShowFontsItem" id="Frm-v0-exu"/>
<toolbarItem implicitItemIdentifier="NSToolbarPrintItem" id="Aqg-6t-nId"/>
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="MMp-QI-cJm"/>
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="8Mn-HP-gRX"/>
</allowedToolbarItems>
<defaultToolbarItems>
<toolbarItem reference="8Mn-HP-gRX"/>
<toolbarItem reference="m2m-v6-Cr4"/>
<toolbarItem reference="Frm-v0-exu"/>
<toolbarItem reference="Aqg-6t-nId"/>
<toolbarItem reference="8Mn-HP-gRX"/>
</defaultToolbarItems>
</toolbar>
<point key="canvasLocation" x="116.5" y="274.5"/>
</window>
</objects>
</document>
//
// PreferenceWindowController.h
// Ring
//
// Created by Alexandre Lision on 2015-02-03.
//
//
#import <Cocoa/Cocoa.h>
@interface PreferencesWindowController : NSWindowController
@end
//
// PreferenceWindowController.m
// Ring
//
// Created by Alexandre Lision on 2015-02-03.
//
//
#import "PreferencesWindowController.h"
@interface PreferencesWindowController ()
@end
@implementation PreferencesWindowController
- (void)windowDidLoad {
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
@end
//
// HistoryTreeController.h
// Ring
//
// Created by Alexandre Lision on 2015-01-28.
//
//
#import <Cocoa/Cocoa.h>
#import <qabstractitemmodel.h>
@interface QNSTreeController : NSTreeController {
QAbstractItemModel *privateQModel;
NSMutableArray* topNodes;
}
- (void*)connect;
- (id) initWithQModel:(QAbstractItemModel*) model;
@end
//
// HistoryTreeController.m
// Ring
//
// Created by Alexandre Lision on 2015-01-28.
//
//
#import "QNSTreeController.h"
#import "MinimalHistoryBackend.h"
@interface Node : NSObject {
NSMutableArray *children;
}
@end
@implementation Node
- (id) init
{
if (self = [super init]) {
children = [[NSMutableArray alloc] init];
}
return self;
}
- (void) addChild:(Node*) child
{
[children addObject:child];
}
- (void) setName: (NSString*) newName
{
#ifdef REARRANGE_FROM_SETNAME
[treeController rearrangeObjects];
#endif
}
@end
@implementation QNSTreeController
- (id) initWithQModel:(QAbstractItemModel*) model
{
[super init];
NSLog(@"init Tree...");
self->privateQModel = model;
topNodes = [[NSMutableArray alloc] init];
[self connect];
return [self initWithContent:topNodes];
}
- (BOOL)isEditable
{
return self->privateQModel->flags(self->privateQModel->index(0, 0)) | Qt::ItemIsEditable;
}
- (void)connect
{
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsInserted,
[=](const QModelIndex & parent, int first, int last) {
for( int row = first; row <= last; row++) {
if(!parent.isValid()) {
//Inserting topnode
Node* n = [[Node alloc] init];
[self insertObject:n atArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndex:row]];
} else {
Node* child = [[Node alloc] init];
NSUInteger indexes[] = { (NSUInteger)parent.row(), (NSUInteger)row};
[self insertObject:child atArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndexes:indexes length:2]];
}
}
}
);
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsAboutToBeMoved,
[=](const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow) {
NSLog(@"rows about to be moved, start: %d, end: %d, moved to: %d", sourceStart, sourceEnd, destinationRow);
/* first remove the row from old location
* then insert them at the new location on the "rowsMoved signal */
for( int row = sourceStart; row <= sourceEnd; row++) {
//TODO
}
}
);
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsMoved,
[=](const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow) {
//NSLog(@"rows moved, start: %d, end: %d, moved to: %d", sourceStart, sourceEnd, destinationRow);
/* these rows should have been removed in the "rowsAboutToBeMoved" handler
* now insert them in the new location */
for( int row = sourceStart; row <= sourceEnd; row++) {
//TODO
}
}
);
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsAboutToBeRemoved,
[=](const QModelIndex & parent, int first, int last) {
//NSLog(@"rows about to be removed");
for( int row = first; row <= last; row++) {
if(topNodes.count <= parent.row())
{
NSUInteger indexes[] = { (NSUInteger)parent.row(), (NSUInteger)row};
[self removeObjectAtArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndexes:indexes length:2]];
} else {
NSLog(@"Removing rows not in tree!");
}
}
}
);
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsAboutToBeRemoved,
[=](const QModelIndex & parent, int first, int last) {
NSLog(@"rows about to be removed");
// for( int row = first; row <= last; row++) {
// if(topNodes.count <= parent.row())
// {
// NSUInteger indexes[] = { (NSUInteger)parent.row(), (NSUInteger)row};
// [self removeObjectAtArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndexes:indexes length:2]];
// } else {
// NSLog(@"Removing rows not in tree!");
// }
// }
}
);
QObject::connect(self->privateQModel,
&QAbstractItemModel::rowsRemoved,
[=](const QModelIndex & parent, int first, int last) {
NSLog(@"rows removed");
for( int row = first; row <= last; row++) {
if(parent.isValid())
{
//Removing leaf
NSUInteger indexes[] = { (NSUInteger)parent.row(), (NSUInteger)row};
[self removeObjectAtArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndexes:indexes length:2]];
} else
{
[self removeObjectAtArrangedObjectIndexPath:[[NSIndexPath alloc] initWithIndex:row]];
}
}
}
);
QObject::connect(self->privateQModel,
&QAbstractItemModel::layoutChanged,
[=]() {
//NSLog(@"layout changed");
}
);