Tanner Bennett лет назад: 6
Родитель
Сommit
a556ece626
22 измененных файлов с 537 добавлено и 501 удалено
  1. 1 1
      Classes/Editing/FLEXMethodCallingViewController.m
  2. 19 0
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDBQueryRowCell.h
  3. 74 0
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDBQueryRowCell.m
  4. 4 3
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDatabaseManager.h
  5. 7 8
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.h
  6. 129 126
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.m
  7. 37 51
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXRealmDatabaseManager.m
  8. 98 87
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLiteDatabaseManager.m
  9. 16 2
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.h
  10. 29 18
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.m
  11. 0 27
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentCell.h
  12. 0 63
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentCell.m
  13. 2 2
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentViewController.h
  14. 66 76
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentViewController.m
  15. 2 2
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableLeftCell.m
  16. 17 24
      Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableListViewController.m
  17. 1 1
      Classes/ObjectExplorers/Sections/FLEXDefaultsContentSection.m
  18. 2 1
      Classes/Utility/Categories/NSArray+Functional.h
  19. 19 0
      Classes/Utility/Categories/NSArray+Functional.m
  20. 1 1
      Classes/Utility/FLEXColor.m
  21. 5 0
      Classes/Utility/FLEXUtility.h
  22. 8 8
      FLEX.xcodeproj/project.pbxproj

+ 1 - 1
Classes/Editing/FLEXMethodCallingViewController.m

@@ -78,7 +78,7 @@
     NSMutableArray *arguments = [NSMutableArray array];
     for (FLEXArgumentInputView *inputView in self.fieldEditorView.argumentInputViews) {
         // Use NSNull as a nil placeholder; it will be interpreted as nil
-        [arguments addObject:inputView.inputValue ?: [NSNull null]];
+        [arguments addObject:inputView.inputValue ?: NSNull.null];
     }
 
     // Call method

+ 19 - 0
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDBQueryRowCell.h

@@ -0,0 +1,19 @@
+//
+//  FLEXDBQueryRowCell.h
+//  FLEX
+//
+//  Created by Peng Tao on 15/11/24.
+//  Copyright © 2015年 f. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+extern NSString * const kFLEXDBQueryRowCellReuse;
+
+
+@interface FLEXDBQueryRowCell : UITableViewCell
+
+/// An array of NSString, NSNumber, or NSData objects
+@property (nonatomic) NSArray *data;
+
+@end

+ 74 - 0
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDBQueryRowCell.m

@@ -0,0 +1,74 @@
+//
+//  FLEXDBQueryRowCell.m
+//  FLEX
+//
+//  Created by Peng Tao on 15/11/24.
+//  Copyright © 2015年 f. All rights reserved.
+//
+
+#import "FLEXDBQueryRowCell.h"
+#import "FLEXMultiColumnTableView.h"
+#import "NSArray+Functional.h"
+#import "UIFont+FLEX.h"
+#import "FLEXColor.h"
+
+NSString * const kFLEXDBQueryRowCellReuse = @"kFLEXDBQueryRowCellReuse";
+
+@interface FLEXDBQueryRowCell ()
+@property (nonatomic) NSInteger columnCount;
+@property (nonatomic) NSArray<UILabel *> *labels;
+@end
+
+@implementation FLEXDBQueryRowCell
+
+- (void)setData:(NSArray *)data {
+    _data = data;
+    self.columnCount = data.count;
+    
+    [self.labels flex_forEach:^(UILabel *label, NSUInteger idx) {
+        id content = self.data[idx];
+        
+        if ([content isKindOfClass:[NSString class]]) {
+            label.text = content;
+        } else if (content == NSNull.null) {
+            label.text = @"<null>";
+            label.textColor = FLEXColor.deemphasizedTextColor;
+        } else {
+            label.text = [content description];
+        }
+    }];
+}
+
+- (void)setColumnCount:(NSInteger)columnCount {
+    if (columnCount != _columnCount) {
+        _columnCount = columnCount;
+        
+        // Remove existing labels
+        for (UILabel *l in self.labels) {
+            [l removeFromSuperview];
+        }
+        
+        // Create new labels
+        self.labels = [NSArray flex_forEachUpTo:columnCount map:^id(NSUInteger i) {
+            UILabel *label = [UILabel new];
+            label.font = UIFont.flex_defaultTableCellFont;
+            label.textAlignment = NSTextAlignmentLeft;
+            [self.contentView addSubview:label];
+            
+            return label;
+        }];
+    }
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    
+    CGFloat width  = self.contentView.frame.size.width / self.labels.count;
+    CGFloat height = self.contentView.frame.size.height;
+    
+    [self.labels flex_forEach:^(UILabel *label, NSUInteger i) {
+        label.frame = CGRectMake(width * i + 5, 0, (width - 10), height);
+    }];
+}
+
+@end

+ 4 - 3
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDatabaseManager.h

@@ -16,11 +16,12 @@
 @protocol FLEXDatabaseManager <NSObject>
 
 @required
-- (instancetype)initWithPath:(NSString*)path;
++ (instancetype)managerForDatabase:(NSString *)path;
 
 - (BOOL)open;
-- (NSArray<NSDictionary<NSString *, id> *> *)queryAllTables;
+/// @return a list of all table names
+- (NSArray<NSString *> *)queryAllTables;
 - (NSArray<NSString *> *)queryAllColumnsWithTableName:(NSString *)tableName;
-- (NSArray<NSDictionary<NSString *, id> *> *)queryAllDataWithTableName:(NSString *)tableName;
+- (NSArray<NSArray *> *)queryAllDataWithTableName:(NSString *)tableName;
 
 @end

+ 7 - 8
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.h

@@ -14,8 +14,8 @@
 @protocol FLEXMultiColumnTableViewDelegate <NSObject>
 
 @required
-- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView didTapLabelWithText:(NSString *)text;
-- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView didTapHeaderWithText:(NSString *)text sortType:(FLEXTableColumnHeaderSortType)sortType;
+- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView didSelectRow:(NSInteger)row;
+- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView didSelectHeaderForColumn:(NSInteger)column sortType:(FLEXTableColumnHeaderSortType)sortType;
 
 @end
 
@@ -25,10 +25,9 @@
 
 - (NSInteger)numberOfColumnsInTableView:(FLEXMultiColumnTableView *)tableView;
 - (NSInteger)numberOfRowsInTableView:(FLEXMultiColumnTableView *)tableView;
-- (NSString *)columnNameInColumn:(NSInteger)column;
-- (NSString *)rowNameInRow:(NSInteger)row;
-- (NSString *)contentAtColumn:(NSInteger)column row:(NSInteger)row;
-- (NSArray *)contentAtRow:(NSInteger)row;
+- (NSString *)columnTitle:(NSInteger)column;
+- (NSString *)rowTitle:(NSInteger)row;
+- (NSArray<NSString *> *)contentForRow:(NSInteger)row;
 
 - (CGFloat)multiColumnTableView:(FLEXMultiColumnTableView *)tableView widthForContentCellInColumn:(NSInteger)column;
 - (CGFloat)multiColumnTableView:(FLEXMultiColumnTableView *)tableView heightForContentCellInRow:(NSInteger)row;
@@ -40,8 +39,8 @@
 
 @interface FLEXMultiColumnTableView : UIView
 
-@property (nonatomic, weak) id<FLEXMultiColumnTableViewDataSource>dataSource;
-@property (nonatomic, weak) id<FLEXMultiColumnTableViewDelegate>delegate;
+@property (nonatomic, weak) id<FLEXMultiColumnTableViewDataSource> dataSource;
+@property (nonatomic, weak) id<FLEXMultiColumnTableViewDelegate> delegate;
 
 - (void)reloadData;
 

+ 129 - 126
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.m

@@ -7,11 +7,13 @@
 //
 
 #import "FLEXMultiColumnTableView.h"
-#import "FLEXTableContentCell.h"
+#import "FLEXDBQueryRowCell.h"
 #import "FLEXTableLeftCell.h"
+#import "FLEXColor.h"
 
-@interface FLEXMultiColumnTableView ()
-<UITableViewDataSource, UITableViewDelegate,UIScrollViewDelegate, FLEXTableContentCellDelegate>
+@interface FLEXMultiColumnTableView () <
+    UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate
+>
 
 @property (nonatomic) UIScrollView *contentScrollView;
 @property (nonatomic) UIScrollView *headerScrollView;
@@ -19,35 +21,49 @@
 @property (nonatomic) UITableView  *contentTableView;
 @property (nonatomic) UIView       *leftHeader;
 
-@property (nonatomic) NSDictionary<NSString *, NSNumber *> *sortStatusDict;
+/// \c NSNotFound if no column selected
+@property (nonatomic) NSInteger sortColumn;
+@property (nonatomic) FLEXTableColumnHeaderSortType sortType;
+
 @property (nonatomic) NSArray *rowData;
+
+@property (nonatomic, readonly) NSInteger numberOfColumns;
+@property (nonatomic, readonly) NSInteger numberOfRows;
+@property (nonatomic, readonly) CGFloat topHeaderHeight;
+@property (nonatomic, readonly) CGFloat leftHeaderWidth;
+@property (nonatomic, readonly) CGFloat columnMargin;
+
 @end
 
 static const CGFloat kColumnMargin = 1;
 
 @implementation FLEXMultiColumnTableView
 
+#pragma mark - Initialization
 
 - (instancetype)initWithFrame:(CGRect)frame {
     self = [super initWithFrame:frame];
     if (self) {
-        [self loadUI];
+        self.autoresizingMask |= UIViewAutoresizingFlexibleWidth;
+        self.autoresizingMask |= UIViewAutoresizingFlexibleHeight;
+        self.autoresizingMask |= UIViewAutoresizingFlexibleTopMargin;
+        self.backgroundColor  = FLEXColor.groupedBackgroundColor;
+        
+        [self loadHeaderScrollView];
+        [self loadContentScrollView];
+        [self loadLeftView];
     }
+    
     return self;
 }
 
-- (void)didMoveToSuperview {
-    [super didMoveToSuperview];
-    [self reloadData];
-}
-
 - (void)layoutSubviews {
     [super layoutSubviews];
     
     CGFloat width  = self.frame.size.width;
     CGFloat height = self.frame.size.height;
-    CGFloat topheaderHeight = [self topHeaderHeight];
-    CGFloat leftHeaderWidth = [self leftHeaderWidth];
+    CGFloat topheaderHeight = self.topHeaderHeight;
+    CGFloat leftHeaderWidth = self.leftHeaderWidth;
     CGFloat topInsets = 0.f;
 
     if (@available (iOS 11.0, *)) {
@@ -55,46 +71,45 @@ static const CGFloat kColumnMargin = 1;
     }
     
     CGFloat contentWidth = 0.0;
-    NSInteger rowsCount = [self numberOfColumns];
+    NSInteger rowsCount = self.numberOfColumns;
     for (int i = 0; i < rowsCount; i++) {
         contentWidth += [self contentWidthForColumn:i];
     }
     
-    self.leftTableView.frame           = CGRectMake(0, topheaderHeight + topInsets, leftHeaderWidth, height - topheaderHeight - topInsets);
-    self.headerScrollView.frame        = CGRectMake(leftHeaderWidth, topInsets, width - leftHeaderWidth, topheaderHeight);
-    self.headerScrollView.contentSize  = CGSizeMake( self.contentTableView.frame.size.width, self.headerScrollView.frame.size.height);
-    self.contentTableView.frame        = CGRectMake(0, 0, contentWidth + [self numberOfColumns] * [self columnMargin] , height - topheaderHeight - topInsets);
-    self.contentScrollView.frame       = CGRectMake(leftHeaderWidth, topheaderHeight + topInsets, width - leftHeaderWidth, height - topheaderHeight - topInsets);
+    CGFloat contentHeight = height - topheaderHeight - topInsets;
+    
+    self.leftHeader.frame = CGRectMake(0, topInsets, self.leftHeaderWidth, self.topHeaderHeight);
+    self.leftTableView.frame = CGRectMake(
+        0, topheaderHeight + topInsets, leftHeaderWidth, contentHeight
+    );
+    self.headerScrollView.frame = CGRectMake(
+        leftHeaderWidth, topInsets, width - leftHeaderWidth, topheaderHeight
+    );
+    self.headerScrollView.contentSize = CGSizeMake(
+        self.contentTableView.frame.size.width, self.headerScrollView.frame.size.height
+    );
+    self.contentTableView.frame = CGRectMake(
+        0, 0, contentWidth + self.numberOfColumns * self.columnMargin , contentHeight
+    );
+    self.contentScrollView.frame = CGRectMake(
+        leftHeaderWidth, topheaderHeight + topInsets, width - leftHeaderWidth, contentHeight
+    );
     self.contentScrollView.contentSize = self.contentTableView.frame.size;
-    self.leftHeader.frame              = CGRectMake(0, topInsets, [self leftHeaderWidth], [self topHeaderHeight]);
 }
 
 
-- (void)loadUI {
-    [self loadHeaderScrollView];
-    [self loadContentScrollView];
-    [self loadLeftView];
-}
-
-- (void)reloadData {
-    [self loadLeftViewData];
-    [self loadContentData];
-    [self loadHeaderData];
-}
-
 #pragma mark - UI
 
 - (void)loadHeaderScrollView {
-    UIScrollView *headerScrollView = [UIScrollView new];
-    headerScrollView.delegate      = self;
-    self.headerScrollView          = headerScrollView;
-    self.headerScrollView.backgroundColor =  [UIColor colorWithWhite:0.803 alpha:0.850];
+    UIScrollView *headerScrollView   = [UIScrollView new];
+    headerScrollView.delegate        = self;
+    headerScrollView.backgroundColor = FLEXColor.secondaryGroupedBackgroundColor;
+    self.headerScrollView            = headerScrollView;
     
     [self addSubview:headerScrollView];
 }
 
 - (void)loadContentScrollView {
-    
     UIScrollView *scrollView = [UIScrollView new];
     scrollView.bounces       = NO;
     scrollView.delegate      = self;
@@ -103,82 +118,89 @@ static const CGFloat kColumnMargin = 1;
     tableView.delegate       = self;
     tableView.dataSource     = self;
     tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+    [tableView registerClass:[FLEXDBQueryRowCell class]
+        forCellReuseIdentifier:kFLEXDBQueryRowCellReuse
+    ];
     
-    [self addSubview:scrollView];
     [scrollView addSubview:tableView];
+    [self addSubview:scrollView];
     
     self.contentScrollView = scrollView;
-    self.contentTableView    = tableView;
-    
+    self.contentTableView  = tableView;
 }
 
 - (void)loadLeftView {
-    UITableView *leftTableView = [UITableView new];
+    UITableView *leftTableView   = [UITableView new];
     leftTableView.delegate       = self;
     leftTableView.dataSource     = self;
     leftTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
     self.leftTableView           = leftTableView;
     [self addSubview:leftTableView];
     
-    UIView *leftHeader = [UIView new];
-    leftHeader.backgroundColor = [UIColor colorWithWhite:0.950 alpha:0.668];
+    UIView *leftHeader         = [UIView new];
+    leftHeader.backgroundColor = FLEXColor.secondaryBackgroundColor;
     self.leftHeader            = leftHeader;
     [self addSubview:leftHeader];
-    
 }
 
 
 #pragma mark - Data
 
+- (void)reloadData {
+    [self loadLeftViewData];
+    [self loadContentData];
+    [self loadHeaderData];
+}
+
 - (void)loadHeaderData {
-    NSArray<UIView *> *subviews = self.headerScrollView.subviews;
-    
-    for (UIView *subview in subviews) {
+    // Remove existing headers, if any
+    for (UIView *subview in self.headerScrollView.subviews) {
         [subview removeFromSuperview];
     }
-    CGFloat x = 0.0;
-    CGFloat w = 0.0;
-    for (int i = 0; i < [self numberOfColumns] ; i++) {
-        w = [self contentWidthForColumn:i] + [self columnMargin];
+    
+    CGFloat xOffset = 0.0;
+    for (NSInteger column = 0; column < self.numberOfColumns; column++) {
+        CGFloat width = [self contentWidthForColumn:column] + self.columnMargin;
         
-        FLEXTableColumnHeader *cell = [[FLEXTableColumnHeader alloc] initWithFrame:CGRectMake(x, 0, w, [self topHeaderHeight] - 1)];
-        cell.label.text = [self columnTitleForColumn:i];
-        [self.headerScrollView addSubview:cell];
+        FLEXTableColumnHeader *header = [[FLEXTableColumnHeader alloc]
+            initWithFrame:CGRectMake(xOffset, 0, width, self.topHeaderHeight - 1)
+        ];
+        header.titleLabel.text = [self columnTitle:column];
         
-        FLEXTableColumnHeaderSortType type = [self.sortStatusDict[[self columnTitleForColumn:i]] integerValue];
-        [cell changeSortStatusWithType:type];
+        if (column == self.sortColumn) {
+            header.sortType = self.sortType;
+        }
         
-        UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self
-                                                                                  action:@selector(contentHeaderTap:)];
-        [cell addGestureRecognizer:gesture];
-        cell.userInteractionEnabled = YES;
+        // Header tap gesture
+        UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc]
+            initWithTarget:self action:@selector(contentHeaderTap:)
+        ];
+        [header addGestureRecognizer:gesture];
+        header.userInteractionEnabled = YES;
         
-        x = x + w;
+        [self.headerScrollView addSubview:header];
+        xOffset += width;
     }
 }
 
 - (void)contentHeaderTap:(UIGestureRecognizer *)gesture {
-    FLEXTableColumnHeader *header = (FLEXTableColumnHeader *)gesture.view;
-    NSString *string = header.label.text;
-    FLEXTableColumnHeaderSortType currentType = [self.sortStatusDict[string] integerValue];
-    FLEXTableColumnHeaderSortType newType ;
+    NSInteger newSortColumn = [self.headerScrollView.subviews indexOfObject:gesture.view];
+    FLEXTableColumnHeaderSortType newType = FLEXNextTableColumnHeaderSortType(self.sortType);
     
-    switch (currentType) {
-        case FLEXTableColumnHeaderSortTypeNone:
-            newType = FLEXTableColumnHeaderSortTypeAsc;
-            break;
-        case FLEXTableColumnHeaderSortTypeAsc:
-            newType = FLEXTableColumnHeaderSortTypeDesc;
-            break;
-        case FLEXTableColumnHeaderSortTypeDesc:
-            newType = FLEXTableColumnHeaderSortTypeAsc;
-            break;
-    }
+    // Reset old header
+    FLEXTableColumnHeader *oldHeader = (id)self.headerScrollView.subviews[self.sortColumn];
+    oldHeader.sortType = FLEXTableColumnHeaderSortTypeNone;
     
-    self.sortStatusDict = @{header.label.text : @(newType)};
-    [header changeSortStatusWithType:newType];
-    [self.delegate multiColumnTableView:self didTapHeaderWithText:string sortType:newType];
+    // Update new header
+    FLEXTableColumnHeader *newHeader = (id)self.headerScrollView.subviews[newSortColumn];
+    newHeader.sortType = newType;
     
+    // Update self
+    self.sortColumn = newSortColumn;
+    self.sortType = newType;
+
+    // Notify delegate
+    [self.delegate multiColumnTableView:self didSelectHeaderForColumn:newSortColumn sortType:newType];
 }
 
 - (void)loadContentData {
@@ -189,39 +211,30 @@ static const CGFloat kColumnMargin = 1;
     [self.leftTableView reloadData];
 }
 
-- (UITableViewCell *)tableView:(UITableView *)tableView
-         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
-    UIColor *backgroundColor = UIColor.whiteColor;
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    // Alternating background color
+    UIColor *backgroundColor = FLEXColor.primaryBackgroundColor;
     if (indexPath.row % 2 != 0) {
-        backgroundColor = [UIColor colorWithWhite:0.950 alpha:0.750];
+        backgroundColor = FLEXColor.secondaryBackgroundColor;
     }
     
-    if (tableView != self.leftTableView) {
-        self.rowData = [self.dataSource contentAtRow:indexPath.row];
-        FLEXTableContentCell *cell = [FLEXTableContentCell cellWithTableView:tableView
-                                                                columnNumber:[self numberOfColumns]];
+    // Left side table view for row numbers
+    if (tableView == self.leftTableView) {
+        FLEXTableLeftCell *cell = [FLEXTableLeftCell cellWithTableView:tableView];
         cell.contentView.backgroundColor = backgroundColor;
-        cell.delegate = self;
-        
-        for (int i = 0 ; i < cell.labels.count; i++) {
-            
-            UILabel *label  = cell.labels[i];
-            label.textColor = UIColor.blackColor;
-            
-            NSString *content = [NSString stringWithFormat:@"%@",self.rowData[i]];
-            if ([content isEqualToString:@"<null>"]) {
-                label.textColor = UIColor.lightGrayColor;
-                content = @"NULL";
-            }
-            label.text            = content;
-            label.backgroundColor = backgroundColor;
-        }
+        cell.titlelabel.text = [self rowTitle:indexPath.row];
         return cell;
     }
+    // Right side table view for data
     else {
-        FLEXTableLeftCell *cell          = [FLEXTableLeftCell cellWithTableView:tableView];
+        self.rowData = [self.dataSource contentForRow:indexPath.row];
+        FLEXDBQueryRowCell *cell = [tableView
+            dequeueReusableCellWithIdentifier:kFLEXDBQueryRowCellReuse forIndexPath:indexPath
+        ];
+        
         cell.contentView.backgroundColor = backgroundColor;
-        cell.titlelabel.text             = [self rowTitleForRow:indexPath.row];
+        cell.data = [self.dataSource contentForRow:indexPath.row];
+        NSAssert(cell.data.count == self.numberOfColumns, @"Count of data provided was incorrect");
         return cell;
     }
 }
@@ -230,12 +243,11 @@ static const CGFloat kColumnMargin = 1;
     return [self.dataSource numberOfRowsInTableView:self];
 }
 
-
 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
     return [self.dataSource multiColumnTableView:self heightForContentCellInRow:indexPath.row];
 }
 
-
+// Scroll all scroll views in sync
 - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
     if (scrollView == self.contentScrollView) {
         self.headerScrollView.contentOffset = scrollView.contentOffset;
@@ -251,23 +263,23 @@ static const CGFloat kColumnMargin = 1;
     }
 }
 
-#pragma mark -
+
 #pragma mark UITableView Delegate
 
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     if (tableView == self.leftTableView) {
-        [self.contentTableView selectRowAtIndexPath:indexPath
-                                           animated:NO
-                                     scrollPosition:UITableViewScrollPositionNone];
+        [self.contentTableView
+            selectRowAtIndexPath:indexPath
+            animated:NO
+            scrollPosition:UITableViewScrollPositionNone
+        ];
     }
     else if (tableView == self.contentTableView) {
-        [self.leftTableView selectRowAtIndexPath:indexPath
-                                        animated:NO
-                                  scrollPosition:UITableViewScrollPositionNone];
+        [self.delegate multiColumnTableView:self didSelectRow:indexPath.row];
     }
 }
 
-#pragma mark -
+
 #pragma mark DataSource Accessor
 
 - (NSInteger)numberOfRows {
@@ -278,16 +290,12 @@ static const CGFloat kColumnMargin = 1;
     return [self.dataSource numberOfColumnsInTableView:self];
 }
 
-- (NSString *)columnTitleForColumn:(NSInteger)column {
-    return [self.dataSource columnNameInColumn:column];
+- (NSString *)columnTitle:(NSInteger)column {
+    return [self.dataSource columnTitle:column];
 }
 
-- (NSString *)rowTitleForRow:(NSInteger)row {
-    return [self.dataSource rowNameInRow:row];
-}
-
-- (NSString *)contentAtColumn:(NSInteger)column row:(NSInteger)row; {
-    return [self.dataSource contentAtColumn:column row:row];
+- (NSString *)rowTitle:(NSInteger)row {
+    return [self.dataSource rowTitle:row];
 }
 
 - (CGFloat)contentWidthForColumn:(NSInteger)column {
@@ -310,9 +318,4 @@ static const CGFloat kColumnMargin = 1;
     return kColumnMargin;
 }
 
-
-- (void)tableContentCell:(FLEXTableContentCell *)tableView labelDidTapWithText:(NSString *)text {
-    [self.delegate multiColumnTableView:self didTapLabelWithText:text];
-}
-
 @end

+ 37 - 51
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXRealmDatabaseManager.m

@@ -7,6 +7,7 @@
 //
 
 #import "FLEXRealmDatabaseManager.h"
+#import "NSArray+Functional.h"
 
 #if __has_include(<Realm/Realm.h>)
 #import <Realm/Realm.h>
@@ -22,88 +23,73 @@
 
 @end
 
-//#endif
-
 @implementation FLEXRealmDatabaseManager
+static Class RLMRealmClass = nil;
+
++ (void)load {
+    RLMRealmClass = NSClassFromString(@"RLMRealm");
+}
+
++ (instancetype)managerForDatabase:(NSString *)path {
+    return [[self alloc] initWithPath:path];
+}
 
-- (instancetype)initWithPath:(NSString*)aPath {
-    Class realmClass = NSClassFromString(@"RLMRealm");
-    if (realmClass == nil) {
+- (instancetype)initWithPath:(NSString *)path {
+    if (!RLMRealmClass) {
         return nil;
     }
     
     self = [super init];
-    
     if (self) {
-        _path = aPath;
+        _path = path;
     }
+    
     return self;
 }
 
 - (BOOL)open {
-    Class realmClass = NSClassFromString(@"RLMRealm");
     Class configurationClass = NSClassFromString(@"RLMRealmConfiguration");
-    
-    if (realmClass == nil || configurationClass == nil) {
+    if (!RLMRealmClass || !configurationClass) {
         return NO;
     }
     
     NSError *error = nil;
     id configuration = [configurationClass new];
     [(RLMRealmConfiguration *)configuration setFileURL:[NSURL fileURLWithPath:self.path]];
-    self.realm = [realmClass realmWithConfiguration:configuration error:&error];
+    self.realm = [RLMRealmClass realmWithConfiguration:configuration error:&error];
+    
     return (error == nil);
 }
 
-- (NSArray<NSDictionary<NSString *, id> *> *)queryAllTables {
-    NSMutableArray<NSDictionary<NSString *, id> *> *allTables = [NSMutableArray array];
-    RLMSchema *schema = [self.realm schema];
-    
-    for (RLMObjectSchema *objectSchema in schema.objectSchema) {
-        if (objectSchema.className == nil) {
-            continue;
-        }
-        
-        NSDictionary<NSString *, id> *dictionary = @{@"name":objectSchema.className};
-        [allTables addObject:dictionary];
-    }
-    
-    return allTables;
+- (NSArray<NSString *> *)queryAllTables {
+    // Map each schema to its name
+    return [self.realm.schema.objectSchema flex_mapped:^id(RLMObjectSchema *schema, NSUInteger idx) {
+        return schema.className ?: nil;
+    }];
 }
 
 - (NSArray<NSString *> *)queryAllColumnsWithTableName:(NSString *)tableName {
-    RLMObjectSchema *objectSchema = [[self.realm schema] schemaForClassName:tableName];
-    if (objectSchema == nil) {
-        return nil;
-    }
-    
-    NSMutableArray<NSString *> *columnNames = [NSMutableArray array];
-    for (RLMProperty *property in objectSchema.properties) {
-        [columnNames addObject:property.name];
-    }
-    
-    return columnNames;
+    RLMObjectSchema *objectSchema = [self.realm.schema schemaForClassName:tableName];
+    // Map each column to its name
+    return [objectSchema.properties flex_mapped:^id(RLMProperty *property, NSUInteger idx) {
+        return property.name;
+    }];
 }
 
-- (NSArray<NSDictionary<NSString *, id> *> *)queryAllDataWithTableName:(NSString *)tableName {
-    RLMObjectSchema *objectSchema = [[self.realm schema] schemaForClassName:tableName];
+- (NSArray<NSArray *> *)queryAllDataWithTableName:(NSString *)tableName {
+    RLMObjectSchema *objectSchema = [self.realm.schema schemaForClassName:tableName];
     RLMResults *results = [self.realm allObjects:tableName];
-    if (results.count == 0 || objectSchema == nil) {
+    if (results.count == 0 || !objectSchema) {
         return nil;
     }
     
-    NSMutableArray<NSDictionary<NSString *, id> *> *allDataEntries = [NSMutableArray array];
-    for (RLMObject *result in results) {
-        NSMutableDictionary<NSString *, id> *entry = [NSMutableDictionary dictionary];
-        for (RLMProperty *property in objectSchema.properties) {
-            id value = [result valueForKey:property.name];
-            entry[property.name] = (value) ? (value) : [NSNull null];
-        }
-        
-        [allDataEntries addObject:entry];
-    }
-    
-    return allDataEntries;
+    // Map results to an array of rows
+    return [NSArray flex_mapped:results block:^id(RLMObject *result, NSUInteger idx) {
+        // Map each row to an array of the values of its properties 
+        return [objectSchema.properties flex_mapped:^id(RLMProperty *property, NSUInteger idx) {
+            return [result valueForKey:property.name] ?: NSNull.null;
+        }];
+    }];
 }
 
 @end

+ 98 - 87
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLiteDatabaseManager.m

@@ -8,22 +8,30 @@
 
 #import "FLEXSQLiteDatabaseManager.h"
 #import "FLEXManager.h"
+#import "NSArray+Functional.h"
 #import <sqlite3.h>
 
+static NSString * const QUERY_TABLENAMES_SQL = @"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
 
-static NSString *const QUERY_TABLENAMES_SQL = @"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
+@interface FLEXSQLiteDatabaseManager ()
+@property (nonatomic, readonly) sqlite3 *db;
+@property (nonatomic, copy) NSString *path;
+@end
+
+@implementation FLEXSQLiteDatabaseManager
 
-@implementation FLEXSQLiteDatabaseManager {
-    sqlite3* _db;
-    NSString* _databasePath;
+#pragma mark - FLEXDatabaseManager
+
++ (instancetype)managerForDatabase:(NSString *)path {
+    return [[self alloc] initWithPath:path];
 }
 
-- (instancetype)initWithPath:(NSString*)aPath {
+- (instancetype)initWithPath:(NSString *)path {
     self = [super init];
-    
     if (self) {
-        _databasePath = [aPath copy];
+        self.path = path;;
     }
+    
     return self;
 }
 
@@ -31,22 +39,22 @@ static NSString *const QUERY_TABLENAMES_SQL = @"SELECT name FROM sqlite_master W
     if (_db) {
         return YES;
     }
-    int err = sqlite3_open(_databasePath.UTF8String, &_db);
+    
+    int err = sqlite3_open(self.path.UTF8String, &_db);
 
 #if SQLITE_HAS_CODEC
-    NSString *defaultSqliteDatabasePassword = [FLEXManager sharedManager].defaultSqliteDatabasePassword;
-
+    NSString *defaultSqliteDatabasePassword = FLEXManager.sharedManager.defaultSqliteDatabasePassword;
     if (defaultSqliteDatabasePassword) {
         const char *key = defaultSqliteDatabasePassword.UTF8String;
-
         sqlite3_key(_db, key, (int)strlen(key));
     }
 #endif
 
-    if(err != SQLITE_OK) {
+    if (err != SQLITE_OK) {
         NSLog(@"error opening!: %d", err);
         return NO;
     }
+    
     return YES;
 }
 
@@ -56,12 +64,11 @@ static NSString *const QUERY_TABLENAMES_SQL = @"SELECT name FROM sqlite_master W
     }
     
     int  rc;
-    BOOL retry;
-    BOOL triedFinalizingOpenStatements = NO;
+    BOOL retry, triedFinalizingOpenStatements = NO;
     
     do {
-        retry   = NO;
-        rc      = sqlite3_close(_db);
+        retry = NO;
+        rc    = sqlite3_close(_db);
         if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
             if (!triedFinalizingOpenStatements) {
                 triedFinalizingOpenStatements = YES;
@@ -72,126 +79,130 @@ static NSString *const QUERY_TABLENAMES_SQL = @"SELECT name FROM sqlite_master W
                     retry = YES;
                 }
             }
-        }
-        else if (SQLITE_OK != rc) {
+        } else if (SQLITE_OK != rc) {
             NSLog(@"error closing!: %d", rc);
         }
-    }
-    while (retry);
+    } while (retry);
     
     _db = nil;
     return YES;
 }
 
-
-- (NSArray<NSDictionary<NSString *, id> *> *)queryAllTables {
-    return [self executeQuery:QUERY_TABLENAMES_SQL];
+- (NSArray<NSString *> *)queryAllTables {
+    return [[self executeQuery:QUERY_TABLENAMES_SQL] flex_mapped:^id(NSArray *table, NSUInteger idx) {
+        return table.firstObject;
+    }];
 }
 
 - (NSArray<NSString *> *)queryAllColumnsWithTableName:(NSString *)tableName {
     NSString *sql = [NSString stringWithFormat:@"PRAGMA table_info('%@')",tableName];
-    NSArray<NSDictionary<NSString *, id> *> *resultArray =  [self executeQuery:sql];
-    NSMutableArray<NSString *> *array = [NSMutableArray array];
-    for (NSDictionary<NSString *, id> *dict in resultArray) {
-        NSString *columnName = (NSString *)dict[@"name"] ?: @"";
-        [array addObject:columnName];
-    }
-    return array;
+    NSArray<NSDictionary *> *results =  [self executeQueryWithColumns:sql];
+    
+    return [results flex_mapped:^id(NSDictionary *column, NSUInteger idx) {
+        return column[@"name"];
+    }];
 }
 
-- (NSArray<NSDictionary<NSString *, id> *> *)queryAllDataWithTableName:(NSString *)tableName {
-    NSString *sql = [NSString stringWithFormat:@"SELECT * FROM %@",tableName];
-    return [self executeQuery:sql];
+- (NSArray<NSArray *> *)queryAllDataWithTableName:(NSString *)tableName {
+    return [self executeQuery:[@"SELECT * FROM "
+        stringByAppendingString:tableName
+    ]];
 }
 
-#pragma mark -
 #pragma mark - Private
 
-- (NSArray<NSDictionary<NSString *, id> *> *)executeQuery:(NSString *)sql {
+/// @return an array of rows, where each row is an array
+/// containing the values of each column for that row
+- (NSArray<NSArray *> *)executeQuery:(NSString *)sql {
     [self open];
-    NSMutableArray<NSDictionary<NSString *, id> *> *resultArray = [NSMutableArray array];
+    
+    NSMutableArray<NSArray *> *results = [NSMutableArray array];
+    
     sqlite3_stmt *pstmt;
     if (sqlite3_prepare_v2(_db, sql.UTF8String, -1, &pstmt, 0) == SQLITE_OK) {
         while (sqlite3_step(pstmt) == SQLITE_ROW) {
-            NSUInteger num_cols = (NSUInteger)sqlite3_data_count(pstmt);
+            int num_cols = sqlite3_data_count(pstmt);
             if (num_cols > 0) {
-                NSMutableDictionary<NSString *, id> *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols];
+                int columnCount = sqlite3_column_count(pstmt);
                 
+                [results addObject:[NSArray flex_forEachUpTo:columnCount map:^id(NSUInteger i) {
+                    return [self objectForColumnIndex:(int)i stmt:pstmt];
+                }]];
+            }
+        }
+    }
+    
+    [self close];
+    return results;
+}
+
+/// Like \c executeQuery: except that a list of dictionaries are returned,
+/// where the keys are column names and the values are the data.
+- (NSArray<NSDictionary *> *)executeQueryWithColumns:(NSString *)sql {
+    [self open];
+    
+    NSMutableArray<NSDictionary *> *results = [NSMutableArray array];
+    
+    sqlite3_stmt *pstmt;
+    if (sqlite3_prepare_v2(_db, sql.UTF8String, -1, &pstmt, 0) == SQLITE_OK) {
+        while (sqlite3_step(pstmt) == SQLITE_ROW) {
+            int num_cols = sqlite3_data_count(pstmt);
+            if (num_cols > 0) {
                 int columnCount = sqlite3_column_count(pstmt);
                 
-                int columnIdx = 0;
-                for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
-                    
-                    NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name(pstmt, columnIdx)];
-                    id objectValue = [self objectForColumnIndex:columnIdx stmt:pstmt];
-                    [dict setObject:objectValue forKey:columnName];
+                
+                NSMutableDictionary *rowFields = [NSMutableDictionary new];
+                for (int i = 0; i < columnCount; i++) {
+                    id value = [self objectForColumnIndex:(int)i stmt:pstmt];
+                    rowFields[@(sqlite3_column_name(pstmt, i))] = value;
                 }
-                [resultArray addObject:dict];
+                
+                [results addObject:rowFields];
             }
         }
     }
+    
     [self close];
-    return resultArray;
+    return results;
 }
 
-
 - (id)objectForColumnIndex:(int)columnIdx stmt:(sqlite3_stmt*)stmt {
     int columnType = sqlite3_column_type(stmt, columnIdx);
     
-    id returnValue = nil;
-    
-    if (columnType == SQLITE_INTEGER) {
-        returnValue =  [NSNumber numberWithLongLong:sqlite3_column_int64(stmt, columnIdx)];
-    }
-    else if (columnType == SQLITE_FLOAT) {
-        returnValue = [NSNumber numberWithDouble:sqlite3_column_double(stmt, columnIdx)];
-    }
-    else if (columnType == SQLITE_BLOB) {
-        returnValue = [self dataForColumnIndex:columnIdx stmt:stmt];
-    }
-    else {
-        //default to a string for everything else
-        returnValue = [self stringForColumnIndex:columnIdx stmt:stmt];
-    }
-    
-    if (returnValue == nil) {
-        returnValue = [NSNull null];
+    switch (columnType) {
+        case SQLITE_INTEGER:
+            return @(sqlite3_column_int64(stmt, columnIdx)).stringValue;
+        case SQLITE_FLOAT:
+            return  @(sqlite3_column_double(stmt, columnIdx)).stringValue;
+        case SQLITE_BLOB:
+            return [NSString stringWithFormat:@"Data (%@ bytes)",
+                @([self dataForColumnIndex:columnIdx stmt:stmt].length)
+            ];
+            
+        default:
+            // Default to a string for everything else
+            return [self stringForColumnIndex:columnIdx stmt:stmt] ?: NSNull.null;
     }
-    
-    return returnValue;
 }
 
 - (NSString *)stringForColumnIndex:(int)columnIdx stmt:(sqlite3_stmt *)stmt {
-    
-    if (sqlite3_column_type(stmt, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
+    if (sqlite3_column_type(stmt, columnIdx) == SQLITE_NULL || columnIdx < 0) {
         return nil;
     }
     
-    const char *c = (const char *)sqlite3_column_text(stmt, columnIdx);
-    
-    if (!c) {
-        // null row.
-        return nil;
-    }
-    
-    return [NSString stringWithUTF8String:c];
+    const char *text = (const char *)sqlite3_column_text(stmt, columnIdx);
+    return text ? @(text) : nil;
 }
 
-- (NSData *)dataForColumnIndex:(int)columnIdx stmt:(sqlite3_stmt *)stmt{
-    
+- (NSData *)dataForColumnIndex:(int)columnIdx stmt:(sqlite3_stmt *)stmt {
     if (sqlite3_column_type(stmt, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
         return nil;
     }
     
-    const char *dataBuffer = sqlite3_column_blob(stmt, columnIdx);
-    int dataSize = sqlite3_column_bytes(stmt, columnIdx);
-    
-    if (dataBuffer == NULL) {
-        return nil;
-    }
+    const void *blob = sqlite3_column_blob(stmt, columnIdx);
+    NSInteger size = (NSInteger)sqlite3_column_bytes(stmt, columnIdx);
     
-    return [NSData dataWithBytes:(const void *)dataBuffer length:(NSUInteger)dataSize];
+    return blob ? [NSData dataWithBytes:blob length:size] : nil;
 }
 
-
 @end

+ 16 - 2
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.h

@@ -14,11 +14,25 @@ typedef NS_ENUM(NSUInteger, FLEXTableColumnHeaderSortType) {
     FLEXTableColumnHeaderSortTypeDesc,
 };
 
+NS_INLINE FLEXTableColumnHeaderSortType FLEXNextTableColumnHeaderSortType(
+    FLEXTableColumnHeaderSortType current) {
+    switch (current) {
+        case FLEXTableColumnHeaderSortTypeAsc:
+            return FLEXTableColumnHeaderSortTypeDesc;
+        case FLEXTableColumnHeaderSortTypeNone:
+        case FLEXTableColumnHeaderSortTypeDesc:
+            return FLEXTableColumnHeaderSortTypeAsc;
+    }
+    
+    return FLEXTableColumnHeaderSortTypeNone;
+}
+
 @interface FLEXTableColumnHeader : UIView
 
-@property (nonatomic) UILabel *label;
+@property (nonatomic) NSInteger index;
+@property (nonatomic, readonly) UILabel *titleLabel;
 
-- (void)changeSortStatusWithType:(FLEXTableColumnHeaderSortType)type;
+@property (nonatomic) FLEXTableColumnHeaderSortType sortType;
 
 @end
 

+ 29 - 18
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.m

@@ -7,36 +7,41 @@
 //
 
 #import "FLEXTableColumnHeader.h"
+#import "FLEXColor.h"
+#import "UIFont+FLEX.h"
+#import "FLEXUtility.h"
 
-@implementation FLEXTableColumnHeader {
-    UILabel *_arrowLabel;
-}
+@interface FLEXTableColumnHeader ()
+@property (nonatomic, readonly) UILabel *arrowLabel;
+@property (nonatomic, readonly) UIView *lineView;
+@end
 
+@implementation FLEXTableColumnHeader
 
 - (instancetype)initWithFrame:(CGRect)frame {
     self = [super initWithFrame:frame];
     if (self) {
-        self.backgroundColor = UIColor.whiteColor;
+        self.backgroundColor = FLEXColor.secondaryBackgroundColor;
         
-        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, frame.size.width - 25, frame.size.height)];
-        label.font = [UIFont systemFontOfSize:13.0];
-        [self addSubview:label];
-        self.label = label;
+        _titleLabel = [UILabel new];
+        _titleLabel.font = UIFont.flex_defaultTableCellFont;
+        [self addSubview:_titleLabel];
         
-        
-        _arrowLabel = [[UILabel alloc] initWithFrame:CGRectMake(frame.size.width - 20, 0, 20, frame.size.height)];
-        _arrowLabel.font = [UIFont systemFontOfSize:13.0];
+        _arrowLabel = [UILabel new];
+        _arrowLabel.font = UIFont.flex_defaultTableCellFont;
         [self addSubview:_arrowLabel];
         
-        UIView *line = [[UIView alloc] initWithFrame:CGRectMake(frame.size.width - 1, 2, 1, frame.size.height - 4)];
-        line.backgroundColor = [UIColor colorWithWhite:0.803 alpha:0.850];
-        [self addSubview:line];
+        _lineView = [UIView new];
+        _lineView.backgroundColor = FLEXColor.hairlineColor;
+        [self addSubview:_lineView];
         
     }
     return self;
 }
 
-- (void)changeSortStatusWithType:(FLEXTableColumnHeaderSortType)type {
+- (void)setSortType:(FLEXTableColumnHeaderSortType)type {
+    _sortType = type;
+    
     switch (type) {
         case FLEXTableColumnHeaderSortTypeNone:
             _arrowLabel.text = @"";
@@ -50,8 +55,14 @@
     }
 }
 
-
-
-
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    
+    CGSize size = self.frame.size;
+    
+    self.titleLabel.frame = CGRectMake(5, 0, size.width - 25, size.height);
+    self.arrowLabel.frame = CGRectMake(size.width - 20, 0, 20, size.height);
+    self.lineView.frame = CGRectMake(size.width - 1, 2, FLEXPointsToPixels(1), size.height - 4);
+}
 
 @end

+ 0 - 27
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentCell.h

@@ -1,27 +0,0 @@
-//
-//  FLEXTableContentCell.h
-//  FLEX
-//
-//  Created by Peng Tao on 15/11/24.
-//  Copyright © 2015年 f. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@class FLEXTableContentCell;
-@protocol FLEXTableContentCellDelegate <NSObject>
-
-@optional
-- (void)tableContentCell:(FLEXTableContentCell *)tableView labelDidTapWithText:(NSString *)text;
-
-@end
-
-@interface FLEXTableContentCell : UITableViewCell
-
-@property (nonatomic) NSArray<UILabel *> *labels;
-
-@property (nonatomic, weak) id<FLEXTableContentCellDelegate> delegate;
-
-+ (instancetype)cellWithTableView:(UITableView *)tableView columnNumber:(NSInteger)number;
-
-@end

+ 0 - 63
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentCell.m

@@ -1,63 +0,0 @@
-//
-//  FLEXTableContentCell.m
-//  FLEX
-//
-//  Created by Peng Tao on 15/11/24.
-//  Copyright © 2015年 f. All rights reserved.
-//
-
-#import "FLEXTableContentCell.h"
-#import "FLEXMultiColumnTableView.h"
-
-@interface FLEXTableContentCell ()
-
-@end
-
-@implementation FLEXTableContentCell
-
-+ (instancetype)cellWithTableView:(UITableView *)tableView columnNumber:(NSInteger)number; {
-    static NSString *identifier = @"FLEXTableContentCell";
-    FLEXTableContentCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
-    if (!cell) {
-        cell = [[FLEXTableContentCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
-        NSMutableArray<UILabel *> *labels = [NSMutableArray array];
-        for (int i = 0; i < number ; i++) {
-            UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
-            label.backgroundColor = UIColor.whiteColor;
-            label.font            = [UIFont systemFontOfSize:13.0];
-            label.textAlignment   = NSTextAlignmentLeft;
-            label.backgroundColor = UIColor.greenColor;
-            [labels addObject:label];
-            
-            UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:cell
-                                                                                      action:@selector(labelDidTap:)];
-            [label addGestureRecognizer:gesture];
-            label.userInteractionEnabled = YES;
-            
-            [cell.contentView addSubview:label];
-            cell.contentView.backgroundColor = UIColor.whiteColor;
-        }
-        cell.labels = labels;
-    }
-    return cell;
-}
-
-- (void)layoutSubviews {
-    [super layoutSubviews];
-    CGFloat labelWidth  = self.contentView.frame.size.width / self.labels.count;
-    CGFloat labelHeight = self.contentView.frame.size.height;
-    for (int i = 0; i < self.labels.count; i++) {
-        UILabel *label = self.labels[i];
-        label.frame = CGRectMake(labelWidth * i + 5, 0, (labelWidth - 10), labelHeight);
-    }
-}
-
-
-- (void)labelDidTap:(UIGestureRecognizer *)gesture {
-    UILabel *label = (UILabel *)gesture.view;
-    if ([self.delegate respondsToSelector:@selector(tableContentCell:labelDidTapWithText:)]) {
-        [self.delegate tableContentCell:self labelDidTapWithText:label.text];
-    }
-}
-
-@end

+ 2 - 2
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentViewController.h

@@ -10,7 +10,7 @@
 
 @interface FLEXTableContentViewController : UIViewController
 
-@property (nonatomic) NSArray<NSString *> *columnsArray;
-@property (nonatomic) NSArray<NSDictionary<NSString *, id> *> *contentsArray;
+@property (nonatomic) NSArray<NSString *> *columns;
+@property (nonatomic) NSArray<NSArray *> *rows;
 
 @end

+ 66 - 76
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentViewController.m

@@ -9,12 +9,12 @@
 #import "FLEXTableContentViewController.h"
 #import "FLEXMultiColumnTableView.h"
 #import "FLEXWebViewController.h"
+#import "FLEXUtility.h"
 
-
-@interface FLEXTableContentViewController ()<FLEXMultiColumnTableViewDataSource, FLEXMultiColumnTableViewDelegate>
-
+@interface FLEXTableContentViewController () <
+    FLEXMultiColumnTableViewDataSource, FLEXMultiColumnTableViewDelegate
+>
 @property (nonatomic) FLEXMultiColumnTableView *multiColumnView;
-
 @end
 
 @implementation FLEXTableContentViewController
@@ -22,6 +22,8 @@
 - (void)viewDidLoad {
     [super viewDidLoad];
     self.edgesForExtendedLayout = UIRectEdgeNone;
+    
+    
     [self.view addSubview:self.multiColumnView];
 }
 
@@ -30,60 +32,39 @@
     [self.multiColumnView reloadData];
 }
 
-#pragma mark -
-
-#pragma mark init SubView
 - (FLEXMultiColumnTableView *)multiColumnView {
     if (!_multiColumnView) {
-        _multiColumnView = [[FLEXMultiColumnTableView alloc] initWithFrame:
-                           CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
+        _multiColumnView = [[FLEXMultiColumnTableView alloc]
+            initWithFrame:FLEXRectSetSize(CGRectZero, self.view.frame.size)
+        ];
         
-        _multiColumnView.autoresizingMask          = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
-        _multiColumnView.backgroundColor           = UIColor.whiteColor;
-        _multiColumnView.dataSource                = self;
-        _multiColumnView.delegate                  = self;
+        _multiColumnView.dataSource       = self;
+        _multiColumnView.delegate         = self;
     }
+    
     return _multiColumnView;
 }
+
 #pragma mark MultiColumnTableView DataSource
 
 - (NSInteger)numberOfColumnsInTableView:(FLEXMultiColumnTableView *)tableView {
-    return self.columnsArray.count;
+    return self.columns.count;
 }
-- (NSInteger)numberOfRowsInTableView:(FLEXMultiColumnTableView *)tableView {
-    return self.contentsArray.count;
-}
-
 
-- (NSString *)columnNameInColumn:(NSInteger)column {
-    return self.columnsArray[column];
+- (NSInteger)numberOfRowsInTableView:(FLEXMultiColumnTableView *)tableView {
+    return self.rows.count;
 }
 
-
-- (NSString *)rowNameInRow:(NSInteger)row {
-    return [NSString stringWithFormat:@"%ld",(long)row];
+- (NSString *)columnTitle:(NSInteger)column {
+    return self.columns[column];
 }
 
-- (NSString *)contentAtColumn:(NSInteger)column row:(NSInteger)row {
-    if (self.contentsArray.count > row) {
-        NSDictionary<NSString *, id> *dic = self.contentsArray[row];
-        if (self.contentsArray.count > column) {
-            return [NSString stringWithFormat:@"%@",[dic objectForKey:self.columnsArray[column]]];
-        }
-    }
-    return @"";
+- (NSString *)rowTitle:(NSInteger)row {
+    return @(row).stringValue;
 }
 
-- (NSArray *)contentAtRow:(NSInteger)row {
-    NSMutableArray *result = [NSMutableArray array];
-    if (self.contentsArray.count > row) {
-        NSDictionary<NSString *, id> *dic = self.contentsArray[row];
-        for (int i = 0; i < self.columnsArray.count; i ++) {
-            [result addObject:dic[self.columnsArray[i]]];
-        }
-        return result;
-    }
-    return nil;
+- (NSArray *)contentForRow:(NSInteger)row {
+    return self.rows[row];
 }
 
 - (CGFloat)multiColumnTableView:(FLEXMultiColumnTableView *)tableView
@@ -101,48 +82,58 @@
 }
 
 - (CGFloat)widthForLeftHeaderInTableView:(FLEXMultiColumnTableView *)tableView {
-    NSString *str = [NSString stringWithFormat:@"%lu",(unsigned long)self.contentsArray.count];
-    NSDictionary<NSString *, id> *attrs = @{@"NSFontAttributeName":[UIFont systemFontOfSize:17.0]};
-    CGSize size =   [str boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 14)
-                                      options:NSStringDrawingUsesLineFragmentOrigin
-                                   attributes:attrs context:nil].size;
+    NSString *str = [NSString stringWithFormat:@"%lu",(unsigned long)self.rows.count];
+    NSDictionary *attrs = @{ NSFontAttributeName : [UIFont systemFontOfSize:17.0] };
+    CGSize size = [str boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 14)
+        options:NSStringDrawingUsesLineFragmentOrigin
+        attributes:attrs context:nil
+    ].size;
+    
     return size.width + 20;
 }
 
-#pragma mark -
-#pragma mark MultiColumnTableView Delegate
 
+#pragma mark MultiColumnTableView Delegate
 
-- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView didTapLabelWithText:(NSString *)text {
-    FLEXWebViewController * detailViewController = [[FLEXWebViewController alloc] initWithText:text];
-    [self.navigationController pushViewController:detailViewController animated:YES];
+- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView didSelectRow:(NSInteger)row {
+    NSArray<NSString *> *fields = [self.rows[row] flex_mapped:^id(NSString *field, NSUInteger idx) {
+        return [NSString stringWithFormat:@"%@:\n%@", self.columns[idx], field];
+    }];
+    
+    [FLEXAlert makeAlert:^(FLEXAlert *make) {
+        make.title([@"Row " stringByAppendingString:@(row).stringValue]);
+        make.message([fields componentsJoinedByString:@"\n\n"]);
+        make.button(@"Dismiss").cancelStyle();
+    } showFrom:self];
 }
 
-- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView didTapHeaderWithText:(NSString *)text sortType:(FLEXTableColumnHeaderSortType)sortType {
+- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView
+    didSelectHeaderForColumn:(NSInteger)column
+                    sortType:(FLEXTableColumnHeaderSortType)sortType {
     
-    NSArray<NSDictionary<NSString *, id> *> *sortContentData = [self.contentsArray sortedArrayUsingComparator:^NSComparisonResult(NSDictionary<NSString *, id> * obj1, NSDictionary<NSString *, id> * obj2) {
-        
-        if ([obj1 objectForKey:text] == [NSNull null]) {
-            return NSOrderedAscending;
-        }
-        if ([obj2 objectForKey:text] == [NSNull null]) {
-            return NSOrderedDescending;
-        }
-        
-        if (![[obj1 objectForKey:text] respondsToSelector:@selector(compare:)] && ![[obj2 objectForKey:text] respondsToSelector:@selector(compare:)]) {
+    NSArray<NSArray *> *sortContentData = [self.rows
+        sortedArrayUsingComparator:^NSComparisonResult(NSArray *obj1, NSArray *obj2) {
+            id a = obj1[column], b = obj2[column];
+            if (a == NSNull.null) {
+                return NSOrderedAscending;
+            }
+            if (b == NSNull.null) {
+                return NSOrderedDescending;
+            }
+            
+            if ([a respondsToSelector:@selector(compare:)] && [b respondsToSelector:@selector(compare:)]) {
+                return [a compare:b];
+            }
+            
             return NSOrderedSame;
         }
-        
-        NSComparisonResult result =  [[obj1 objectForKey:text] compare:[obj2 objectForKey:text]];
-        
-        return result;
-    }];
+    ];
+    
     if (sortType == FLEXTableColumnHeaderSortTypeDesc) {
-        NSEnumerator *contentReverseEnumerator = sortContentData.reverseObjectEnumerator;
-        sortContentData = [NSArray arrayWithArray:contentReverseEnumerator.allObjects];
+        sortContentData = sortContentData.reverseObjectEnumerator.allObjects.copy;
     }
     
-    self.contentsArray = sortContentData;
+    self.rows = sortContentData;
     [self.multiColumnView reloadData];
 }
 
@@ -151,19 +142,18 @@
 
 - (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection
               withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator {
-    [super willTransitionToTraitCollection:newCollection
-                 withTransitionCoordinator:coordinator];
+    [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator];
+    
     [coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) {
         if (newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {
-            
-            self->_multiColumnView.frame = CGRectMake(0, 32, self.view.frame.size.width, self.view.frame.size.height - 32);
+            self.multiColumnView.frame = CGRectMake(0, 32, self.view.frame.size.width, self.view.frame.size.height - 32);
         }
         else {
-            self->_multiColumnView.frame = CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64);
+            self.multiColumnView.frame = CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64);
         }
+        
         [self.view setNeedsLayout];
     } completion:nil];
 }
 
-
 @end

+ 2 - 2
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableLeftCell.m

@@ -16,13 +16,13 @@
     
     if (!cell) {
         cell = [[FLEXTableLeftCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
-        UILabel *textLabel               = [[UILabel alloc] initWithFrame:CGRectZero];
+        UILabel *textLabel               = [UILabel new];
         textLabel.textAlignment          = NSTextAlignmentCenter;
         textLabel.font                   = [UIFont systemFontOfSize:13.0];
-        textLabel.backgroundColor = UIColor.clearColor;
         [cell.contentView addSubview:textLabel];
         cell.titlelabel = textLabel;
     }
+    
     return cell;
 }
 

+ 17 - 24
Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableListViewController.m

@@ -7,17 +7,15 @@
 //
 
 #import "FLEXTableListViewController.h"
-
 #import "FLEXDatabaseManager.h"
 #import "FLEXSQLiteDatabaseManager.h"
 #import "FLEXRealmDatabaseManager.h"
-
 #import "FLEXTableContentViewController.h"
+#import "NSArray+Functional.h"
 
-@interface FLEXTableListViewController () {
-    id<FLEXDatabaseManager> _dbm;
-    NSString *_databasePath;
-}
+@interface FLEXTableListViewController ()
+@property (nonatomic, readonly) id<FLEXDatabaseManager> dbm;
+@property (nonatomic, readonly) NSString *path;
 
 @property (nonatomic) NSArray<NSString *> *tables;
 @property (nonatomic) NSArray<NSString *> *filteredTables;
@@ -32,9 +30,9 @@
 - (instancetype)initWithPath:(NSString *)path {
     self = [super initWithStyle:UITableViewStyleGrouped];
     if (self) {
-        _databasePath = [path copy];
-        _dbm = [self databaseManagerForFileAtPath:_databasePath];
-        [_dbm open];
+        _path = [path copy];
+        _dbm = [self databaseManagerForFileAtPath:self.path];
+        [self.dbm open];
         [self getAllTables];
     }
     return self;
@@ -45,26 +43,19 @@
     
     NSArray<NSString *> *sqliteExtensions = [FLEXTableListViewController supportedSQLiteExtensions];
     if ([sqliteExtensions indexOfObject:pathExtension] != NSNotFound) {
-        return [[FLEXSQLiteDatabaseManager alloc] initWithPath:path];
+        return [FLEXSQLiteDatabaseManager managerForDatabase:path];
     }
     
     NSArray<NSString *> *realmExtensions = [FLEXTableListViewController supportedRealmExtensions];
     if (realmExtensions != nil && [realmExtensions indexOfObject:pathExtension] != NSNotFound) {
-        return [[FLEXRealmDatabaseManager alloc] initWithPath:path];
+        return [FLEXRealmDatabaseManager managerForDatabase:path];
     }
     
     return nil;
 }
 
 - (void)getAllTables {
-    NSArray<NSDictionary<NSString *, id> *> *resultArray = [_dbm queryAllTables];
-    NSMutableArray<NSString *> *array = [NSMutableArray array];
-    for (NSDictionary<NSString *, id> *dict in resultArray) {
-        NSString *columnName = (NSString *)dict[@"name"] ?: @"";
-        [array addObject:columnName];
-    }
-    self.tables = array;
-    self.filteredTables = array;
+    self.tables = self.filteredTables = [self.dbm queryAllTables];;
 }
 
 - (void)viewDidLoad {
@@ -76,12 +67,14 @@
 #pragma mark - Search bar
 
 - (void)updateSearchResults:(NSString *)searchText {
-    if (searchText.length > 0) {
-        NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] %@", searchText];
-        self.filteredTables = [self.tables filteredArrayUsingPredicate:searchPredicate];
+    if (searchText.length) {
+        self.filteredTables = [self.tables flex_filtered:^BOOL(NSString *tableName, NSUInteger idx) {
+            return [tableName containsString:searchText];
+        }];
     } else {
         self.filteredTables = self.tables;
     }
+    
     [self.tableView reloadData];
 }
 
@@ -106,8 +99,8 @@
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     FLEXTableContentViewController *contentViewController = [FLEXTableContentViewController new];
     
-    contentViewController.contentsArray = [_dbm queryAllDataWithTableName:self.filteredTables[indexPath.row]];
-    contentViewController.columnsArray = [_dbm queryAllColumnsWithTableName:self.filteredTables[indexPath.row]];
+    contentViewController.rows = [self.dbm queryAllDataWithTableName:self.filteredTables[indexPath.row]];
+    contentViewController.columns = [self.dbm queryAllColumnsWithTableName:self.filteredTables[indexPath.row]];
     
     contentViewController.title = self.filteredTables[indexPath.row];
     [self.navigationController pushViewController:contentViewController animated:YES];

+ 1 - 1
Classes/ObjectExplorers/Sections/FLEXDefaultsContentSection.m

@@ -75,7 +75,7 @@
 
     // Generate new dictionary from whitelisted keys
     NSArray *values = [self.defaults.dictionaryRepresentation
-        objectsForKeys:self.keys notFoundMarker:[NSNull null]
+        objectsForKeys:self.keys notFoundMarker:NSNull.null
     ];
     return [NSDictionary dictionaryWithObjects:values forKeys:self.keys];
 }

+ 2 - 1
Classes/Utility/Categories/NSArray+Functional.h

@@ -24,7 +24,8 @@
 /// \c maxLength is greater than 1, you get an array with 1 element back.
 - (instancetype)flex_subArrayUpto:(NSUInteger)maxLength;
 
-+ (instancetype)flex_forEachUpTo:(NSUInteger)bound map:(T(^)(NSUInteger))block;
++ (instancetype)flex_forEachUpTo:(NSUInteger)bound map:(T(^)(NSUInteger i))block;
++ (instancetype)flex_mapped:(id<NSFastEnumeration>)collection block:(id(^)(T obj, NSUInteger idx))mapFunc;
 
 - (instancetype)sortedUsingSelector:(SEL)selector;
 

+ 19 - 0
Classes/Utility/Categories/NSArray+Functional.m

@@ -85,6 +85,25 @@
     return array;
 }
 
+
++ (instancetype)flex_mapped:(id<NSFastEnumeration>)collection block:(id(^)(id obj, NSUInteger idx))mapFunc {
+    NSMutableArray *array = [NSMutableArray new];
+    NSInteger idx = 0;
+    for (id obj in collection) {
+        id ret = mapFunc(obj, idx++);
+        if (ret) {
+            [array addObject:ret];
+        }
+    }
+
+    // For performance reasons, don't copy large arrays
+    if (array.count < 2048) {
+        return array.copy;
+    }
+
+    return array;
+}
+
 - (instancetype)sortedUsingSelector:(SEL)selector {
     if (FLEXArrayClassIsMutable(self)) {
         NSMutableArray *me = (id)self;

+ 1 - 1
Classes/Utility/FLEXColor.m

@@ -130,7 +130,7 @@
 }
 
 + (UIColor *)hairlineColor {
-    return FLEXDynamicColor(systemGrayColor, grayColor);
+    return FLEXDynamicColor(systemGray3Color, colorWithWhite:0.75 alpha:1);
 }
 
 + (UIColor *)destructiveColor {

+ 5 - 0
Classes/Utility/FLEXUtility.h

@@ -25,6 +25,11 @@ NS_INLINE CGFloat FLEXFloor(CGFloat x) {
     return floor(UIScreen.mainScreen.scale * (x)) / UIScreen.mainScreen.scale;
 }
 
+/// Returns the given number of points in pixels
+NS_INLINE CGFloat FLEXPointsToPixels(CGFloat points) {
+    return points / UIScreen.mainScreen.scale;
+}
+
 /// Creates a CGRect with all members rounded down to the nearest "point" coordinate
 NS_INLINE CGRect FLEXRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height) {
     return CGRectMake(FLEXFloor(x), FLEXFloor(y), FLEXFloor(width), FLEXFloor(height));

+ 8 - 8
FLEX.xcodeproj/project.pbxproj

@@ -117,8 +117,8 @@
 		779B1ED11C0C4D7C001F5E49 /* FLEXMultiColumnTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 779B1EC31C0C4D7C001F5E49 /* FLEXMultiColumnTableView.m */; };
 		779B1ED21C0C4D7C001F5E49 /* FLEXTableColumnHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 779B1EC41C0C4D7C001F5E49 /* FLEXTableColumnHeader.h */; };
 		779B1ED31C0C4D7C001F5E49 /* FLEXTableColumnHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 779B1EC51C0C4D7C001F5E49 /* FLEXTableColumnHeader.m */; };
-		779B1ED41C0C4D7C001F5E49 /* FLEXTableContentCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 779B1EC61C0C4D7C001F5E49 /* FLEXTableContentCell.h */; };
-		779B1ED51C0C4D7C001F5E49 /* FLEXTableContentCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 779B1EC71C0C4D7C001F5E49 /* FLEXTableContentCell.m */; };
+		779B1ED41C0C4D7C001F5E49 /* FLEXDBQueryRowCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 779B1EC61C0C4D7C001F5E49 /* FLEXDBQueryRowCell.h */; };
+		779B1ED51C0C4D7C001F5E49 /* FLEXDBQueryRowCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 779B1EC71C0C4D7C001F5E49 /* FLEXDBQueryRowCell.m */; };
 		779B1ED61C0C4D7C001F5E49 /* FLEXTableContentViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 779B1EC81C0C4D7C001F5E49 /* FLEXTableContentViewController.h */; };
 		779B1ED71C0C4D7C001F5E49 /* FLEXTableContentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 779B1EC91C0C4D7C001F5E49 /* FLEXTableContentViewController.m */; };
 		779B1ED81C0C4D7C001F5E49 /* FLEXTableLeftCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 779B1ECA1C0C4D7C001F5E49 /* FLEXTableLeftCell.h */; };
@@ -458,8 +458,8 @@
 		779B1EC31C0C4D7C001F5E49 /* FLEXMultiColumnTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXMultiColumnTableView.m; sourceTree = "<group>"; };
 		779B1EC41C0C4D7C001F5E49 /* FLEXTableColumnHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXTableColumnHeader.h; sourceTree = "<group>"; };
 		779B1EC51C0C4D7C001F5E49 /* FLEXTableColumnHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXTableColumnHeader.m; sourceTree = "<group>"; };
-		779B1EC61C0C4D7C001F5E49 /* FLEXTableContentCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXTableContentCell.h; sourceTree = "<group>"; };
-		779B1EC71C0C4D7C001F5E49 /* FLEXTableContentCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXTableContentCell.m; sourceTree = "<group>"; };
+		779B1EC61C0C4D7C001F5E49 /* FLEXDBQueryRowCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXDBQueryRowCell.h; sourceTree = "<group>"; };
+		779B1EC71C0C4D7C001F5E49 /* FLEXDBQueryRowCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXDBQueryRowCell.m; sourceTree = "<group>"; };
 		779B1EC81C0C4D7C001F5E49 /* FLEXTableContentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXTableContentViewController.h; sourceTree = "<group>"; };
 		779B1EC91C0C4D7C001F5E49 /* FLEXTableContentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEXTableContentViewController.m; sourceTree = "<group>"; };
 		779B1ECA1C0C4D7C001F5E49 /* FLEXTableLeftCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEXTableLeftCell.h; sourceTree = "<group>"; };
@@ -971,8 +971,8 @@
 				779B1EC31C0C4D7C001F5E49 /* FLEXMultiColumnTableView.m */,
 				779B1EC41C0C4D7C001F5E49 /* FLEXTableColumnHeader.h */,
 				779B1EC51C0C4D7C001F5E49 /* FLEXTableColumnHeader.m */,
-				779B1EC61C0C4D7C001F5E49 /* FLEXTableContentCell.h */,
-				779B1EC71C0C4D7C001F5E49 /* FLEXTableContentCell.m */,
+				779B1EC61C0C4D7C001F5E49 /* FLEXDBQueryRowCell.h */,
+				779B1EC71C0C4D7C001F5E49 /* FLEXDBQueryRowCell.m */,
 				779B1EC81C0C4D7C001F5E49 /* FLEXTableContentViewController.h */,
 				779B1EC91C0C4D7C001F5E49 /* FLEXTableContentViewController.m */,
 				779B1ECA1C0C4D7C001F5E49 /* FLEXTableLeftCell.h */,
@@ -1446,7 +1446,7 @@
 				3A4C95011B5B21410088C3F2 /* FLEXArgumentInputTextView.h in Headers */,
 				C36FBFCC230F3B98008D95D5 /* FLEXProtocolBuilder.h in Headers */,
 				C36FBFDB230F3B98008D95D5 /* FLEXClassBuilder.h in Headers */,
-				779B1ED41C0C4D7C001F5E49 /* FLEXTableContentCell.h in Headers */,
+				779B1ED41C0C4D7C001F5E49 /* FLEXDBQueryRowCell.h in Headers */,
 				C301994A2409B38A00759E8E /* CALayer+FLEX.h in Headers */,
 				3A4C952C1B5B21410088C3F2 /* FLEXLiveObjectsTableViewController.h in Headers */,
 				3A4C94EF1B5B21410088C3F2 /* FLEXArgumentInputDateView.h in Headers */,
@@ -1698,7 +1698,7 @@
 				3A4C94DE1B5B21410088C3F2 /* FLEXHeapEnumerator.m in Sources */,
 				3A4C95251B5B21410088C3F2 /* FLEXFileBrowserTableViewController.m in Sources */,
 				C36FBFD1230F3B98008D95D5 /* FLEXClassBuilder.m in Sources */,
-				779B1ED51C0C4D7C001F5E49 /* FLEXTableContentCell.m in Sources */,
+				779B1ED51C0C4D7C001F5E49 /* FLEXDBQueryRowCell.m in Sources */,
 				3A4C94E21B5B21410088C3F2 /* FLEXResources.m in Sources */,
 				94A515281C4CA2080063292F /* FLEXToolbarItem.m in Sources */,
 				3A4C95311B5B21410088C3F2 /* FLEXSystemLogMessage.m in Sources */,