Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 197 additions & 0 deletions Documentation/NSDataLinkDelegateCallbacks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# NSDataLink and NSDataLinkManager Delegate Callback Enhancements

## Overview

This update enhances NSDataLink and NSDataLinkManager with comprehensive delegate callbacks that provide fine-grained control over link management, updates, and visual feedback.

## New Delegate Methods Implemented

### Link Tracking Callbacks

#### `dataLinkManager:startTrackingLink:`
- Called when a new link is added to the manager
- Triggered by `addLink:at:` and `addSourceLink:` methods
- Allows delegates to set up monitoring or UI elements for the link

#### `dataLinkManager:stopTrackingLink:`
- Called when a link is removed or broken
- Triggered by `removeLink:`, `breakAllLinks`, and individual link breaks
- Allows delegates to clean up resources associated with the link

### Update Management Callbacks

#### `dataLinkManager:isUpdateNeededForLink:`
- Called to check if a link needs updating
- Used by file monitoring system and manual update checks
- Delegates can implement custom logic to determine update necessity
- Considers file modification times, user preferences, etc.

#### `dataLinkManagerRedrawLinkOutlines:`
- Called when link outline visibility changes
- Triggered by `setLinkOutlinesVisible:` and `redrawLinkOutlines`
- Allows UI to refresh link visual indicators

#### `dataLinkManagerTracksLinksIndividually:`
- Queries the delegate about tracking behavior
- Returns whether links should be monitored individually
- Affects performance and granularity of updates

### Enhanced Document Status Callbacks

#### `dataLinkManagerDidEditLinks:`
- Enhanced to be called during document editing and reverting
- Provides consistent notification of link changes

#### `dataLinkManagerCloseDocument:`
- Called when document is closing
- Allows cleanup of delegate resources

## New Public Methods

### NSDataLinkManager

#### `addSourceLink:`
- Convenience method for adding source links
- Includes proper delegate notifications
- Manages source link collection

#### `removeLink:`
- Safely removes links from both source and destination collections
- Includes proper delegate notifications
- Ensures consistent cleanup

#### `checkForLinkUpdates`
- Manually triggers update checking for all destination links
- Uses `isUpdateNeededForLink:` delegate callback
- Performs actual updates when needed

#### `redrawLinkOutlines`
- Manually triggers outline redraw
- Calls `dataLinkManagerRedrawLinkOutlines:` delegate method

#### `tracksLinksIndividually`
- Queries delegate about tracking preferences
- Returns boolean indicating tracking mode

### Enhanced Document Management

#### `noteDocumentSaved`
- Now updates all source link timestamps
- Triggers update checking for destination links
- Provides comprehensive save handling

#### `noteDocumentSavedAs:`
- Updates internal filename reference
- Calls standard save handling
- Maintains link consistency across file operations

#### `noteDocumentSavedTo:`
- Updates source link filenames when applicable
- Handles "Save As" scenarios properly
- Maintains link integrity

## Enhanced NSDataLink Methods

#### `updateDestination`
- Now consults delegate via `isUpdateNeededForLink:`
- Updates timestamp on successful update
- Provides better control over update process

## File Monitoring Integration

The file monitoring system now integrates with delegate callbacks:

- File change detection triggers `isUpdateNeededForLink:`
- Automatic updates respect delegate decisions
- Provides seamless integration between file system events and application logic

## Usage Examples

### Basic Delegate Implementation

```objectivec
@interface MyDelegate : NSObject
@end

@implementation MyDelegate

- (void)dataLinkManager:(NSDataLinkManager *)sender
startTrackingLink:(NSDataLink *)link
{
// Set up UI elements, start monitoring, etc.
[self addLinkToUI: link];
}

- (BOOL)dataLinkManager:(NSDataLinkManager *)sender
isUpdateNeededForLink:(NSDataLink *)link
{
// Custom update logic
return [self shouldUpdateLink: link];
}

- (void)dataLinkManagerRedrawLinkOutlines:(NSDataLinkManager *)sender
{
// Refresh visual indicators
[self refreshLinkOutlines];
}

@end
```

### Integration with Applications

```objectivec
// Initialize with delegate
MyDelegate *delegate = [[MyDelegate alloc] init];
NSDataLinkManager *manager = [[NSDataLinkManager alloc]
initWithDelegate: delegate];

// Add links with automatic delegate notification
NSDataLink *link = [[NSDataLink alloc] initLinkedToFile: @"source.txt"];
[manager addSourceLink: link]; // Triggers startTrackingLink:

// Manual update checking
[manager checkForLinkUpdates]; // Uses isUpdateNeededForLink:

// Visual management
[manager setLinkOutlinesVisible: YES]; // Triggers redraw callback
```

## Benefits

1. **Fine-grained Control**: Delegates have complete control over link lifecycle
2. **Performance Optimization**: Custom update logic prevents unnecessary operations
3. **UI Integration**: Comprehensive callbacks for visual feedback
4. **Resource Management**: Proper cleanup notifications prevent leaks
5. **Consistency**: All link operations now provide delegate notifications
6. **Flexibility**: Delegates can implement custom policies for updates and tracking

## Backward Compatibility

All enhancements maintain full backward compatibility with existing code. Applications not implementing the new delegate methods will continue to work with default behaviors.

## Implementation Details

### Files Modified

- **NSDataLinkManager.h**: Added new method declarations
- **NSDataLinkManager.m**: Implemented all delegate callback integration
- **NSDataLink.m**: Enhanced `updateDestination` method with delegate consultation

### Key Changes

1. All link addition/removal methods now call appropriate tracking delegates
2. File monitoring system integrates with `isUpdateNeededForLink:` callback
3. Document save operations trigger comprehensive link updates
4. Outline visibility changes trigger redraw callbacks
5. Enhanced error handling and resource cleanup

### Testing

The implementation includes a comprehensive example (`NSDataLinkExample.m`) that demonstrates:

- Delegate method implementation
- Link lifecycle management
- Update checking integration
- Visual feedback handling
- Resource cleanup
166 changes: 166 additions & 0 deletions Examples/NSDataLinkExample.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/**
* Example demonstrating NSDataLink delegate callbacks
*
* This example shows how to implement the NSDataLinkManager delegate methods
* to handle link tracking, updates, and outline drawing.
*/

#import <Foundation/Foundation.h>
#import "AppKit/NSDataLinkManager.h"
#import "AppKit/NSDataLink.h"
#import "AppKit/NSSelection.h"
#import "AppKit/NSPasteboard.h"

@interface DataLinkDelegate : NSObject
{
NSMutableArray *_trackedLinks;
}
@end

@implementation DataLinkDelegate

- (id) init
{
if ((self = [super init]))
{
_trackedLinks = [[NSMutableArray alloc] init];
}
return self;
}

- (void) dealloc
{
[_trackedLinks release];
[super dealloc];
}

// Required delegate methods for link management
- (void)dataLinkManager: (NSDataLinkManager *)sender
startTrackingLink: (NSDataLink *)link
{
NSLog(@"Started tracking link #%d", [link linkNumber]);
[_trackedLinks addObject: link];
}

- (void)dataLinkManager: (NSDataLinkManager *)sender
stopTrackingLink: (NSDataLink *)link
{
NSLog(@"Stopped tracking link #%d", [link linkNumber]);
[_trackedLinks removeObject: link];
}

- (void)dataLinkManager: (NSDataLinkManager *)sender
didBreakLink: (NSDataLink *)link
{
NSLog(@"Link #%d was broken", [link linkNumber]);
[_trackedLinks removeObject: link];
}

- (BOOL)dataLinkManager: (NSDataLinkManager *)sender
isUpdateNeededForLink: (NSDataLink *)link
{
// Check if the source has been modified since last update
NSDate *lastUpdate = [link lastUpdateTime];
NSString *sourceFile = [link sourceFilename];

if (sourceFile)
{
NSDictionary *attrs = [[NSFileManager defaultManager]
attributesOfItemAtPath: sourceFile error: nil];
NSDate *modDate = [attrs objectForKey: NSFileModificationDate];

if (modDate && lastUpdate && [modDate compare: lastUpdate] == NSOrderedDescending)
{
NSLog(@"Update needed for link #%d - source modified", [link linkNumber]);
return YES;
}
}

return NO;
}

- (void)dataLinkManagerDidEditLinks: (NSDataLinkManager *)sender
{
NSLog(@"Document links were edited");
}

- (void)dataLinkManagerRedrawLinkOutlines: (NSDataLinkManager *)sender
{
NSLog(@"Should redraw link outlines (visibility: %s)",
[sender areLinkOutlinesVisible] ? "visible" : "hidden");
}

- (BOOL)dataLinkManagerTracksLinksIndividually: (NSDataLinkManager *)sender
{
NSLog(@"Using individual link tracking");
return YES; // Enable individual tracking
}

- (void)dataLinkManagerCloseDocument: (NSDataLinkManager *)sender
{
NSLog(@"Document is closing, cleaning up %lu tracked links",
(unsigned long)[_trackedLinks count]);
}

// Optional selection management methods
- (BOOL)copyToPasteboard: (NSPasteboard *)pasteboard
at: (NSSelection *)selection
cheapCopyAllowed: (BOOL)flag
{
NSLog(@"Copy to pasteboard requested for selection");
return YES;
}

- (BOOL)showSelection: (NSSelection *)selection
{
NSLog(@"Show selection requested");
return YES;
}

@end

// Example usage
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

DataLinkDelegate *delegate = [[DataLinkDelegate alloc] init];
NSDataLinkManager *manager = [[NSDataLinkManager alloc]
initWithDelegate: delegate];

// Create a test link
NSDataLink *link = [[NSDataLink alloc] initLinkedToFile: @"/tmp/test.txt"];

// Add the link - this will trigger startTrackingLink delegate callback
NSLog(@"Adding link...");
[manager addSourceLink: link];

// Test update checking
NSLog(@"Checking for updates...");
[manager checkForLinkUpdates];

// Test outline visibility changes
NSLog(@"Setting outline visibility...");
[manager setLinkOutlinesVisible: YES];
[manager setLinkOutlinesVisible: NO];

// Test manual redraw
NSLog(@"Manual redraw...");
[manager redrawLinkOutlines];

// Test tracking mode
NSLog(@"Individual tracking: %s",
[manager tracksLinksIndividually] ? "YES" : "NO");

// Remove the link - this will trigger stopTrackingLink delegate callback
NSLog(@"Removing link...");
[manager removeLink: link];

// Cleanup
[link release];
[manager release];
[delegate release];
[pool release];

return 0;
}
2 changes: 2 additions & 0 deletions Headers/Additions/GNUstepGUI/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS

/* Do we have inotify */
#undef HAVE_INOTIFY_H

/* Define for those who don't have rintf and/or rint */
#ifndef HAVE_RINTF
Expand Down
Loading