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
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2026 Genetec Inc.
// Licensed under the Apache License, Version 2.0

namespace Genetec.Dap.CodeSamples;

using Sdk;
using Sdk.Events.AccessPoint;
using Sdk.Queries;
using Sdk.Queries.AccessControl;
using Sdk.Workspace;
using Sdk.Workspace.Components.TimelineProvider;
using Sdk.Workspace.Pages.Contents;
using System;
using System.Data;
using System.Linq;
using System.Threading.Tasks;

public class AccessControlTimelineProvider : TimelineProvider, IDisposable
{
private readonly Workspace m_workspace;

public AccessControlTimelineProvider(Workspace workspace)
{
m_workspace = workspace;
m_workspace.Sdk.EventReceived += OnEventReceived;
}

public override void Query(ContentGroup contentGroup, DateTime startTime, DateTime endTime)
{
Task.Run(async () =>
{
var query = (CardholderActivityQuery)m_workspace.Sdk.ReportManager.CreateReportQuery(ReportType.CardholderActivity);
query.TimeRange.SetTimeRange(startTime, endTime);
query.Events.Clear();
query.Events.Add(EventType.AccessGranted);
query.Events.Add(EventType.AccessRefused);

QueryCompletedEventArgs result = await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);

var events = result.Data.AsEnumerable().Select(row =>
{
var timestamp = row.Field<DateTime>(AccessControlReportQuery.TimestampColumnName);
var cardholderGuid = row.Field<Guid>(AccessControlReportQuery.CardholderGuidColumnName);
var eventType = row.Field<EventType>(AccessControlReportQuery.EventTypeColumnName);

return new AccessTimelineEvent(cardholderGuid, timestamp, eventType == EventType.AccessGranted);
});

InsertEvents(events);
OnQueryCompleted();
});
}

private void OnEventReceived(object sender, EventReceivedEventArgs e)
{
switch (e.EventType)
{
case EventType.AccessGranted:
case EventType.AccessRefused:
if (e.Event is AccessEvent accessEvent)
{
var timelineEvent = new AccessTimelineEvent(
accessEvent.Cardholder,
accessEvent.Timestamp,
accessEvent.Type == EventType.AccessGranted);
InsertEvent(timelineEvent);
}
break;
}
}

public void Dispose()
{
m_workspace.Sdk.EventReceived -= OnEventReceived;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2026 Genetec Inc.
// Licensed under the Apache License, Version 2.0

namespace Genetec.Dap.CodeSamples;

using Sdk.Workspace.Components.TimelineProvider;
using System;

public class AccessControlTimelineProviderBuilder : TimelineProviderBuilder
{
public override string Name => nameof(AccessControlTimelineProviderBuilder);

public override string Title => "Access Control Events";

public override Guid UniqueId { get; } = new Guid("8A3C5F12-9D4E-4B7A-B2C1-6E8F0A1D3C5B"); // Replace with your own unique GUID

public override TimelineProvider CreateProvider()
{
return new AccessControlTimelineProvider(Workspace);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2026 Genetec Inc.
// Licensed under the Apache License, Version 2.0

namespace Genetec.Dap.CodeSamples;

using Sdk;
using Sdk.Workspace.Components.TimelineProvider;
using System;
using System.Windows;
using System.Windows.Media;

public class AccessTimelineEvent : TimelineEvent
{
private static readonly Size s_size = new Size(16, 16);

private static readonly ImageSource s_grantedImage;
private static readonly ImageSource s_refusedImage;

private readonly bool m_isGranted;

static AccessTimelineEvent()
{
s_grantedImage = EventType.AccessGranted.GetIcon();
s_refusedImage = EventType.AccessRefused.GetIcon();
}

public AccessTimelineEvent(Guid cardholderGuid, DateTime timestamp, bool isGranted) : base(timestamp)
{
CardholderGuid = cardholderGuid;
m_isGranted = isGranted;
}

public Guid CardholderGuid { get; }

public override TimelineVisual GetVisual(Rect constraint, double msPerPixel)
{
var drawingVisual = new DrawingVisual();

DrawingContext drawingContext = drawingVisual.RenderOpen();

ImageSource image = m_isGranted ? s_grantedImage : s_refusedImage;
drawingContext.DrawImage(image, new Rect(new Point(constraint.X, (constraint.Height - 16) / 2), s_size));

drawingContext.Close();

return new TimelineVisual(drawingVisual)
{
AlignmentY = AlignmentY.Center,
AlignmentX = AlignmentX.Center
};
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2025 Genetec Inc.
// Copyright 2026 Genetec Inc.
// Licensed under the Apache License, Version 2.0

namespace Genetec.Dap.CodeSamples;
Expand All @@ -13,24 +13,14 @@ namespace Genetec.Dap.CodeSamples;
using Sdk.Workspace.Components.TimelineProvider;
using Sdk.Workspace.Pages.Contents;

public class AlarmTimelineProvider : TimelineProvider
public class AlarmTimelineProvider : TimelineProvider, IDisposable
{
private readonly Workspace m_workspace;

public AlarmTimelineProvider(Workspace workspace)
{
m_workspace = workspace;

workspace.Sdk.AlarmAcknowledged += OnAlarmAcknowledged;

void OnAlarmAcknowledged(object sender, AlarmAcknowledgedEventArgs e)
{
foreach (AlarmTimelineEvent timelineEvent in GetEvents().OfType<AlarmTimelineEvent>()
.Where(timelineEvent => timelineEvent.AlarmGuid == e.AlarmGuid && timelineEvent.InstanceId == e.InstanceId))
{
RemoveEvent(timelineEvent);
}
}
m_workspace.Sdk.AlarmAcknowledged += OnAlarmAcknowledged;
}

public override void Query(ContentGroup contentGroup, DateTime startTime, DateTime endTime)
Expand All @@ -50,11 +40,26 @@ public override void Query(ContentGroup contentGroup, DateTime startTime, DateTi
var alarmGuid = row.Field<Guid>(AlarmActivityQuery.AlarmColumnName);
var instanceId = row.Field<int>(AlarmActivityQuery.InstanceIdColumnName);
var triggerTime = row.Field<DateTime>(AlarmActivityQuery.TriggerTimeColumnName);

return new AlarmTimelineEvent(alarmGuid, instanceId, triggerTime);
});

InsertEvents(events);
OnQueryCompleted();
});
}
}

private void OnAlarmAcknowledged(object sender, AlarmAcknowledgedEventArgs e)
{
foreach (AlarmTimelineEvent timelineEvent in GetEvents().OfType<AlarmTimelineEvent>()
.Where(t => t.AlarmGuid == e.AlarmGuid && t.InstanceId == e.InstanceId))
{
RemoveEvent(timelineEvent);
}
}

public void Dispose()
{
m_workspace.Sdk.AlarmAcknowledged -= OnAlarmAcknowledged;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@

namespace Genetec.Dap.CodeSamples;

using System;
using Sdk.Workspace.Components.TimelineProvider;
using System;

public class AlarmTimelineProviderBuilder : TimelineProviderBuilder
{
public override string Name => nameof(AlarmTimelineProviderBuilder);

public override string Title => "Active Alarms";

public override Guid UniqueId { get; } = new Guid("4765D714-2BD6-42A8-99E3-0A0767C76321");
public override Guid UniqueId { get; } = new Guid("4765D714-2BD6-42A8-99E3-0A0767C76321"); // Replace with your own unique GUID

public override TimelineProvider CreateProvider()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<ClientCertificate>
<CompanyName>Genetec</CompanyName>
<ApplicationName>Demo Certificate for SDK Development only</ApplicationName>
<ApplicationId>KxsD11z743Hf5Gq9mv3+5ekxzemlCiUXkTFY5ba1NOGcLCmGstt2n0zYE9NsNimv</ApplicationId>
</ClientCertificate>
31 changes: 27 additions & 4 deletions Samples/Workspace SDK/TimelineProviderSample/SampleModule.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,47 @@
// Copyright 2025 Genetec Inc.
// Copyright 2026 Genetec Inc.
// Licensed under the Apache License, Version 2.0

namespace Genetec.Dap.CodeSamples;

using Genetec.Sdk.Workspace.Components;
using Sdk;
using Sdk.Workspace.Modules;

public class SampleModule : Module
{
private AlarmTimelineProviderBuilder m_alarmBuilder;
private AccessControlTimelineProviderBuilder m_accessControlBuilder;

public override void Load()
{
if (Workspace.ApplicationType == ApplicationType.SecurityDesk)
{
var builder = new AlarmTimelineProviderBuilder();
builder.Initialize(Workspace);
Workspace.Components.Register(builder);
m_alarmBuilder = new AlarmTimelineProviderBuilder();
Register(m_alarmBuilder);

m_accessControlBuilder = new AccessControlTimelineProviderBuilder();
Register(m_accessControlBuilder);

void Register(Component component)
{
component.Initialize(Workspace);
Workspace.Components.Register(component);
}
}
}

public override void Unload()
{
if (m_alarmBuilder != null)
{
Workspace.Components.Unregister(m_alarmBuilder);
m_alarmBuilder = null;
}

if (m_accessControlBuilder != null)
{
Workspace.Components.Unregister(m_accessControlBuilder);
m_accessControlBuilder = null;
}
}
}