Update existing Google calendar entry using TMS Cloud component - delphi

I use the following code to add a new entry to my Google calendar using TMS Cloud component
I have the new entries in a table in a database and they are added OK
But I would like to be able to update an entry also, but that I cant find any help about.
The demo that is supplied with the controls has the option, but I don't want to load all entries from the calendar and select the one to edit there. I want to save some sort of entryID that it is given and use that to update.
DevExpress has an option that lets you sync a table to and from Outlook calendar (works very nice) so I think it should be possible to do with TMS
The question is: how do I get an ID of a calendar entry when creating it so I can store it with the record in table and use it afterwards for updating?
var
ci: TGCalendarItem;
begin
AdvGCalendar.App.Key := Settings.Google.Key;
AdvGCalendar.App.Secret := Settings.Google.Secret;
AdvGCalendar.Logging := true;
if not AdvGCalendar.TestTokens then
AdvGCalendar.RefreshAccess;
if not AdvGCalendar.TestTokens then
AdvGCalendar.DoAuth
else
Connected := True;
ci := AdvGCalendar.Items.Add;
AdvGCalendar.GetCalendars();
ci.CalendarID := Settings.Google.Calendar;
if ci.CalendarID <> '' then
begin
ci.Location := CiLocation;
ci.Description := CiDescription;
ci.Summary := CiSummary;
ci.StartTime := EncodeDateTime(YearOf(StartDate), MonthOf(StartDate), DayOf(StartDate), HourOf(StartTime), MinuteOf(StartTime), 0, 0);
ci.EndTime := EncodeDateTime(YearOf(StopDate), MonthOf(StopDate), DayOf(StopDate), HourOf(StopTime), MinuteOf(StopTime), 0, 0);
ci.IsAllDay := False;
ci.Visibility := viPrivate;
AdvGCalendar.Add(ci);
end;
end;

The problem was related to the fact that there was an error in the version I was using of the component so that the ID was not returned OK.
Upgrading to a newer version fixed this so now it is working.

Related

Create TVirtualTable via Code only without drop component

Recently i want to export data using TscExcelExport.
If i'm using TVirtualTable using Design Component, it works perfectly.
EmpVT.First;
EmpVT.Filtered := False;
while not EmpVT.Eof do
begin
//Salary Virtual Table
VirtualTableBankTransferListExport.Append;
VirtualTableBankTransferListExport.FieldByName('EMPID').AsInteger := EmpVT.FieldByName('EMPID').AsInteger;
VirtualTableBankTransferListExport.FieldByName('EMPBANKGROUPNO').AsInteger := EmpVT.FieldByName('BANKGROUPNO').AsInteger;
VirtualTableBankTransferListExport.FieldByName('EMPTRANSBANKACCNAME').AsString := EmpVT.FieldByName('EMPBANKACCNAME').AsString;
VirtualTableBankTransferListExport.FieldByName('EMPTRANSBANKACCNO').AsString := EmpVT.FieldByName('EMPBANKACCNO').AsString;
VirtualTableBankTransferListExport.FieldByName('BANKACCNO').AsString := EmpVT.FieldByName('BANKACCNO').AsString;
VirtualTableBankTransferListExport.FieldByName('PERIOD').AsString := PaySlipPeriod;
VirtualTableBankTransferListExport.FieldByName('BANKNAME').AsString := EmpVT.FieldByName('BANKNAME').AsString;
VirtualTableBankTransferList.FieldByName('TRANSFERAMOUNT').AsInteger := 0;//Format('%s%s%.*d', [EmpVT.FieldByName('REGIONCODE').AsString,EmpVT.FieldByName('EMPCODE').AsString,4,EmpVT.FieldByName('EMPCODE').AsInteger]); //EmpVT.FieldByName('EMPCODE').AsString;
VirtualTableBankTransferListExport.FieldByName('BANKID').AsString := EmpVT.FieldByName('BANKID').AsString;
VirtualTableBankTransferListExport.FieldByName('TBANKNAME').AsString := EmpVT.FieldByName('TBANKNAME').AsString;
VirtualTableBankTransferListExport.FieldByName('BANKLOCATION').AsString := EmpVT.FieldByName('BANKLOCATION').AsString;
VirtualTableBankTransferListExport.Post;
EmpVT.Next;
end;
scExcelExport1.WorksheetName := 'Bank Transfer List';
scExcelExport1.Dataset:=VirtualTableBankTransferListExport;
scExcelExport1.ExportDataset;
scExcelExport1.Disconnect;
What is the correct way to create TVirtualTable via Code only without dropping TVirtualTable in form?
Thank you for your help.
Install CnWizards (more features but less stable) or GExperts IDE (more polished but less features) add-on
They both have "Component-To-Code" wizard.
So you would select your component, run this command from the menu and would get the pure Pascal sources of creating it.
PS. Actually there might be several components, not a single one: fields are usually components of their own.

Refresh Query / cxGrid

Using Delphi XE2.
I am writing a software package which uses cxGrids and are linked to Querys/Datasources.
At a click of a button how do you refresh a Query to make sure the records are up to date in the cxGrids.
Also if a record is highlighted on a cxGrid it must remember that record and doesn't reset back to the top of the grid.
Close and open the dataset behind the cxgrid to make sure you have the latest data.
dataset.close;
dataset.open;
If you need to remember the current record and put the cursor back on it - use a bookmark as shown in the link below.
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/DB_TDataSet_GetBookmark.html
If you prefer not to use a bookmark, you can utilise the dataset.locate method.
Store the primary key of the record, and after the refresh, use dataset.locate(dataset.fieldbyname('PK').AsDataType) to take you back to that record.
Using the locate method is probably a more readable/elegant way of working.
for cxgrid of devexpress the bookmaker is a bad solution for restore the selection , you can use the cxStatusKeeper ( it public unit that you can download from support center of devexpress )
{Init the component for restore selection}
FGridStatus := TcxGridDBTableKeeper.Create(self);
FGridStatus.LoadExpanding := False;
FGridStatus.LoadSelection := True;
FGridStatus.LoadFocus := True;
FGridStatus.LoadTopRecord := False;
FGridStatus.LoadWithDetails := False;
FGridStatus.LoadFocusedView := True;
FGridStatus.LoadFocusedItem := True;
FGridStatus.View := gvTableElementi;
{save the current items}
FGridStatus.Store;
{restore the selection}
if FGridStatus.GridStored then
FGridStatus.Restore;
cxGridTableView.Navigator has a Refresh button that will do what you want.
If you want to Refresh using your own button, you can call cxGridTableView.DataController.RefreshExternalData

Find deleted appointment in Outlook from Delphi

I am attempting to integrate our program with outlook and my test code below (sort of works) but have the following issues.
In testing I was able to add the appointment. Then manually moved the appointment to another date/time and re-ran the test program and it moved back (as expected). But...
when an item is deleted the code below is still able to locate the item (somehow!). I even manually removed the item from the Deleted Items folder in Outlook.
as a result,since it 'found' the appointment, it then attempts to update it, resulting in a AV as well. I suspect there is something wrong in my use of the find function, but what I am trying to do is to use userProperties to add something from our system to add into the appointment item in outlook and update if needed. But also needs to be able to handle the case where a user might manually delete item from calendar as well.
Any assistance would be greatly appreciated.
folder := ns.GetDefaultFolder(olFolderCalendar);
if not VarIsNull(folder) and not VarIsEmpty(folder) then
begin
try
appointment := folder.Items.Find('[MyRecProperty2]=' + quotedStr(1001));
entryFound := true;
except
end;
if (not entryFound) or
(varType(Appointment)=varNull) or
(varType(Appointment)=varEmpty) then
begin
appointment := folder.Items.Add(olAppointmentItem);
prop := appointment.UserProperties.Add('MyRecProperty2',olText,True);
prop.Value := '1001';
NewAppointment(appointment);
end
else
begin
showmessage('updating appointment!');
FillAppointment(appointment, false);
end;
showmessage('saving appointment!');
appointment.Save;
//showmessage('display appointment!');
//appointment.Display(true);

Creating extended property using EWS and access it from Outlook Add-in

I am currently working on EWS to have some integration of our company application with Exchange 2010. I am using EWS to create appoinment to Exchange 2010 and it works fine; but recently I tried to add some custom/extended property when creating the appointment, below is my code to add the extended property.
Dim customField As New ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "MyCustomField", MapiPropertyType.String)
appointment.SetExtendedProperty(customField, "CustomFieldValue")
The above codes able to create the custom field to the appointment.
Now here is my problem. When I open up the appointment in Outlook that I created and go to "Developer > Design This Form", then "All Fields" tab, I only see the custom field I created in the "User-defined field in folder" but not in "User-defined field in this item".
I also making an Outlook Add-in to react to the custom field that I created using the EWS when user opens up the appointment in Outlook, when I tried to look for the custom field, couldn't find the custom field, because the custom field is created in "User-defined field in folder" but not in "User-defined field in this item".
This is the codes in the Outlook Add-in and will execute when user opens an apointment in Outlook. But because the custom field is not in "in this item", the .Find() returns Nothing.
Dim appt As Outlook.AppointmentItem
appt = TryCast(inspector.CurrentItem, Outlook.AppointmentItem)
If appt.UserProperties.Find("MyCustomField") Is Nothing Then
'Some action
Else
'Some action
End If
What I want to achieve is to create an appointment with the custom field (extended property) using EWS, and then read the custom field (extended property) in Outlook Add-in when user open the appointment in Outlook.
EDIT:
The value that I assigned to the custom field using EWS is shown in the "User-defined field in folder". How do I retrieve the value from my Outlook Add-in? Maybe I can retrieve the value and add the custom field to the item and with the value?
Thanks.
The answer is here:
http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/2a98b4ab-0fbc-4863-8303-48711a18a050
Can't access the extended property created by EWS using UserProperties. But can access using PropertyAccessor.
outlookItem.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/yourProp")
I'm posting this as another answer showing some actual (Delphi) code, because that was missing from the first answer.
AAppointmentItem is an OLEVariant
const
GUID_PS_PUBLIC_STRINGS = '{00020329-0000-0000-C000-000000000046}';
cPublicStringNameSpace = 'http://schemas.microsoft.com/mapi/string/' + GUID_PS_PUBLIC_STRINGS + '/';
var
lPropertyAccessor: OleVariant;
lSchemaName, lValue: String;
begin
// Use the PropertyAccessor because Outlook UserProperties() can't access the extended properties created by EWS
// Use the 'string subnamespace of the MAPI namespace' (http://msdn.microsoft.com/en-us/library/office/ff868915.aspx)
// with the PS_PUBLIC_STRINGS GUID from http://msdn.microsoft.com/en-us/library/bb905283%28v=office.12%29.aspx
lPropertyAccessor := AAppointmentItem.PropertyAccessor;
lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLID; // Name constants defined elsewhere
try
lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLID;
lValue := lPropertyAccessor.GetProperty(lSchemaName);
lEvent.CustSyncTTID := StrToInt(lValue);
except
end;
try
lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLSYNCTIME;
lValue := lPropertyAccessor.GetProperty(lSchemaName);
lEvent.CustSyncDate := UTCString2LocalDateTime(lValue);
except
end;
try
lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLSYNCID;
lValue := lPropertyAccessor.GetProperty(lSchemaName);
lEvent.CustSyncEntryID := lValue;
except
end;
Note the many try excepts because we are doing late binding; 'early' would've been better
(http://blog.depauptits.nl/2012/04/safely-accessing-named-properties-in.html)
Also, We are retrieving multiple user properties, so GetProperties() is actually better.
FWIW, this was the old code using UserProperties (lProperty is OLEVariant)
lProperty := AAppointmentItem.UserProperties.Find(PROPERTY_TIMETELLID);
if IDispatch(lProperty) <> nil then
lEvent.CustSyncTTID := lProperty.Value;
lProperty := AAppointmentItem.UserProperties.Find(PROPERTY_TIMETELLSYNCTIME);
if IDispatch(lProperty) <> nil then
lEvent.CustSyncDate := lProperty.Value;
lProperty := AAppointmentItem.UserProperties.Find(PROPERTY_TIMETELLSYNCID);
if IDispatch(lProperty) <> nil then
lEvent.CustSyncEntryID := lProperty.Value;
[Edited to add 2013-6-10]
And here is the code modified to handle all three properties at once using GetProperties (as MS recommends):
lPropertyAccessor := AAppointmentItem.PropertyAccessor;
lSchemas := VarArrayOf([cPublicStringNameSpace + PROPERTY_TIMETELLID,
cPublicStringNameSpace + PROPERTY_TIMETELLSYNCTIME,
cPublicStringNameSpace + PROPERTY_TIMETELLSYNCID]);
try
lValues := lPropertyAccessor.GetProperties(lSchemas);
if VarType(lValues[0]) <> varError then
lEvent.CustSyncTTID := lValues[0];
if VarType(lValues[1]) <> varError then
begin
lDT := lValues[1];
lDT := TTimeZone.Local.ToLocalTime(lDT);
lEvent.CustSyncDate := lDT;
end;
if VarType(lValues[2]) <> varError then
lEvent.CustSyncEntryID := lValues[2];
except
end;

How do I sort a CSV file in a TTable?

I have a TTable, and I am loading CSV files to this TTable. Three fields are there: Id, Hits & Path.
I made some lookup fields to this TTable with another query.
I want to sort the table. I am getting the message "Capability not supported." when I try to call AddIndex('ndxHits','HITS',[]);
Here is my code:
with DM.TblCVResults do
begin
try
Active := False;
TableName := 'C:\CSV\123.txt';
Active := True;
AddIndex('ndxHits','HITS',[]);
AddIndex('ndxCandidate','LkCandidate',[]);
AddIndex('ndxLastCV','LkLastCV',[]);
AddIndex('ndxPostCode','LkPostCode',[]);
IndexDefs.Update;
Active := True;
DM.TblCVResults.IndexName := 'ndxHits';
except
on E: Exception do
MsgError(E.Message);
end;
end
Your previous question mentioned you were using ttASCII as the TableType. ttASCII tables, AFAIK, don't support indexes.
Your best bet is to load the ttASCII TTable content into a TClientDataset` (CDS), which does support indexes. I haven't tested with a ttASCII table as the source, but it should be as simple as:
Add a TDatasetProvider component to your application. Set it's DataSet property to your TTable.
Add a TClientDataSet component to your application. Set it's ProviderName to the DataSetProvider you added above. (I've named it CDS in the steps below.)
Open both the Table and the ClientDataSet (CDS), in that order.
Table1.Active := True;
CDS.Active := True;
Turn off updating of the TTable if you don't need it. (It's much faster.)
CDS.LogChanges := False;
Run the following code to create the indexes:
// Repeat for each additional index
with CDS.IndexDefs.AddIndexDef do
begin
Name := 'ndxHits';
Fields := 'Hits';
Options := [];
end;
Set the ClientDataSet's IndexName property to the index you want active:
CDS.IndexName := 'ndxHits';
Use the ClientDataSet like you would any other dataset. Search it using Locate or FindKey, add to it using Insert or Append, filter it, and so forth.

Resources