Resource

Resource Basics

Resource Name Places Hierarchies Mapping to Metadata
Resource Version 0.1
Category Catalog
Downloads 780
Release Date 6/8/2018 4:36:53 PM
 

Resource Details

Description This script is intended to check your Places hierarchy and allows to to define the appropriate mappings to metadata for them.

BEWARE; when changes are made to the catalog labels and you have auto-sync switched ON then this may cause many files to be synced. The script does allow you to select what found labels to update.
Installation Instructions 1. Download the script
Usage Instructions 2. Select Tools -> Scripter
3. Load the script as downloaded before
4. Start the script
Changes in this version n.a.
Special Requirements 4.1
 

Author Information

Author Name IDimager Support
 

Available Attachments

Attachment #1 SelectWhatToMap.png
Attachment #1 SelectCustom.png
Attachment #1 UpdateAll.png
 

Script

var
  ChangeList: TTntStringList;

var
  ConfigForm: TvxSceneForm;
  OffsetLevel: TvxSpinBox;
  CountryMapping: TvxCheckBox;
  StateMapping: TvxCheckBox;
  CityMapping: TvxCheckBox;
  LocationMapping: TvxCheckBox;

  function BuildForm: TvxSceneForm;
  var
    ALabel: TvxLabel;
  begin
    result := TvxSceneForm.Create(nil);

    result.Caption := 'Places Hierarchy Mapping to Metadata';

    ALabel := TvxLabel.Create(result.Root);
    ALabel.Text := 'At what level below the Places category are your Countries? (1 = immediatly under Places):';
    ALabel.TextAlign := vgTextAlignNear;
    ALabel.Padding.Rect := vxRect(15, 35, 5, 5);
    ALabel.Height := 40;
    ALabel.Align := vaTop;
    result.Root.AddObject(ALabel);

    OffsetLevel := TvxSpinBox.Create(result.Root);
    OffsetLevel.Min   := 1;
    OffsetLevel.Max   := 5;
    OffsetLevel.Value := ReadFromRegistry('ScriptPlacesHierarchy', 'OffsetLevel', 1);
    OffsetLevel.Padding.Rect := vxRect(35, 5, result.Width * 0.3, 5);
    OffsetLevel.Align := vaTop;
    result.Root.AddObject(OffsetLevel);

    CountryMapping := TvxCheckBox.Create(result.Root);
    CountryMapping.Text := 'Map Country Catalog Labels';
    CountryMapping.TextAlign := vgTextAlignNear;
    CountryMapping.Padding.Rect := vxRect(35, 5, 5, 5);
    CountryMapping.Align := vaTop;
    CountryMapping.IsChecked := ReadFromRegistry('ScriptPlacesHierarchy', 'CountryMapping', Ord(PublicOptions.XMPSyncReadSettings.GEOLevel) >= Ord(glCountry)) = 1;
    result.Root.AddObject(CountryMapping);

    StateMapping := TvxCheckBox.Create(result.Root);
    StateMapping.Text := 'Map State Catalog Labels';
    StateMapping.TextAlign := vgTextAlignNear;
    StateMapping.Padding.Rect := vxRect(45, 5, 5, 5);
    StateMapping.Align := vaTop;
    StateMapping.IsChecked := ReadFromRegistry('ScriptPlacesHierarchy', 'StateMapping', Ord(PublicOptions.XMPSyncReadSettings.GEOLevel) >= Ord(glState)) = 1;
    result.Root.AddObject(StateMapping);

    CityMapping := TvxCheckBox.Create(result.Root);
    CityMapping.Text := 'Map City Catalog Labels';
    CityMapping.TextAlign := vgTextAlignNear;
    CityMapping.Padding.Rect := vxRect(55, 5, 5, 5);
    CityMapping.Align := vaTop;
    CityMapping.IsChecked := ReadFromRegistry('ScriptPlacesHierarchy', 'CityMapping', Ord(PublicOptions.XMPSyncReadSettings.GEOLevel) >= Ord(glCity)) = 1;
    result.Root.AddObject(CityMapping);

    LocationMapping := TvxCheckBox.Create(result.Root);
    LocationMapping.Text := 'Map Location Catalog Labels';
    LocationMapping.TextAlign := vgTextAlignNear;
    LocationMapping.Padding.Rect := vxRect(65, 5, 5, 5);
    LocationMapping.Align := vaTop;
    LocationMapping.IsChecked := ReadFromRegistry('ScriptPlacesHierarchy', 'LocationMapping', Ord(PublicOptions.XMPSyncReadSettings.GEOLevel) >= Ord(glLocation)) = 1;
    result.Root.AddObject(LocationMapping);
  end;

  procedure HandlePropMapping(AProp: TCatalogItemProp; ALocationLevel: Integer);
  const
    cCountryLevel  = 0;
    cStateLevel    = 1;
    cCityLevel     = 2;
    cLocationLevel = 3;
  var
    ANewLink: WideString;
  begin
    {
    ALocationLevel:
      0 = Country Level:
        photoshop:Country,Iptc4xmpExt:LocationCreated.Iptc4xmpExt:CountryName,Iptc4xmpExt:LocationShown.Iptc4xmpExt:CountryName
      1 = State Level:
        photoshop:State,Iptc4xmpExt:LocationCreated.Iptc4xmpExt:ProvinceState,Iptc4xmpExt:LocationShown.Iptc4xmpExt:ProvinceState
      2 = City Level:
        photoshop:City,Iptc4xmpExt:LocationCreated.Iptc4xmpExt:City,Iptc4xmpExt:LocationShown.Iptc4xmpExt:City
      3 = Location Level:
        Iptc4xmpCore:Location,Iptc4xmpExt:LocationCreated.Iptc4xmpExt:Sublocation,Iptc4xmpExt:LocationShown.Iptc4xmpExt:Sublocation
    }

    ANewLink := AProp.PropXMPLink;
    if (ALocationLevel = cCountryLevel) and (CountryMapping.IsChecked) then
      ANewLink := 'photoshop:Country,Iptc4xmpExt:LocationCreated.Iptc4xmpExt:CountryName,Iptc4xmpExt:LocationShown.Iptc4xmpExt:CountryName'
    else if (ALocationLevel = cStateLevel) and (StateMapping.IsChecked) then
      ANewLink := 'photoshop:State,Iptc4xmpExt:LocationCreated.Iptc4xmpExt:ProvinceState,Iptc4xmpExt:LocationShown.Iptc4xmpExt:ProvinceState'
    else if (ALocationLevel = cCityLevel) and (CityMapping.IsChecked) then
      ANewLink := 'photoshop:City,Iptc4xmpExt:LocationCreated.Iptc4xmpExt:City,Iptc4xmpExt:LocationShown.Iptc4xmpExt:City'
    else if (ALocationLevel = cLocationLevel) and (LocationMapping.IsChecked) then
      ANewLink := 'Iptc4xmpCore:Location,Iptc4xmpExt:LocationCreated.Iptc4xmpExt:Sublocation,Iptc4xmpExt:LocationShown.Iptc4xmpExt:Sublocation';

    if not WideSameText(ANewLink, AProp.PropXMPLink) then
    begin
      ChangeList.Values[AProp.GUID] := ANewLink;
    end;
  end;

  procedure HandlePropsAtLevel(AProps: TCatalogItemProps; ALevel: Integer);
  var
    ASubs: TCatalogItemProps;
    i: Integer;
  begin
    if ALevel >= OffsetLevel.Value then
    begin
      for i := 0 to AProps.Count - 1 do
        HandlePropMapping(AProps.Items[i], ALevel - OffsetLevel.Value);
    end;

    // read subs for next level
    for i := 0 to AProps.Count - 1 do
    begin
      ASubs := TCatalogItemProps.Create(TCatalogItemProp, '');
      try
        PublicCatalog.EnumPropsForParent(AProps.Items[i].GUID, ASubs, False, False);
        HandlePropsAtLevel(ASubs, ALevel + 1);
      finally
        ASubs.Free;
      end;
    end;
  end;

  procedure HandleChangeList;
  var
    i: Integer;
    AGUID, ANewLink: WideString;
    AProps: TCatalogItemProps;
    AProp: TCatalogItemProp;

    ACheckList: TTntStringList;
    AChecked: Boolean;
    ARes: Integer;
  begin
    ACheckList := TTntStringList.Create;
    AProps := TCatalogItemProps.Create(TCatalogItemProp, '');
    try
      for i := 0 to ChangeList.Count - 1 do
      begin
        AGUID := ChangeList.Names[i];
        ANewLink := ChangeList.ValueFromIndex[i];

        AProp := TCatalogItemProp.Create(AProps);
        if Catalog.EnumProp(AGUID, AProp, False) then
        begin
          AProp.ParentXMPLinkAssign := True;
          AProp.PropXMPLink := ANewLink;
          ACheckList.AddObject('?' + PublicCatalog.PathNameForProp(AProp, '::', True), AProp);
        end
        else
          AProp.Free;
      end;

      if Ask2('Would you line to update all ' + IntToStr(ACheckList.Count) + ' found Catalog Labels?', 'select No to manually select the Catalog Labels to update') then
      begin
        ARes := mrOk;
        for i := 0 to ACheckList.Count - 1 do
          ACheckList.Strings[i] := '1' + MidStr(ACheckList.Strings[i], 2, Length(ACheckList.Strings[i]));
      end
      else
      begin
        ARes := AskCustom(
                  'Select the labels to update...',
                  '',
                  '',   // 'info text'
                  '',   // 'check this'
                  AChecked,
                  ACheckList
                );
      end;

      if ARes <> -1 then
      begin
        AHit := 0;
        for i := 0 to ACheckList.Count - 1 do
        begin
          if LeftStr(ACheckList.Strings[i], 1) = '1' then
          begin
            AProp := TCatalogItemProp(ACheckList.Objects[i]);
            PublicCatalog.UpdateProp(AProp);
            AHit := AHit + 1;
          end;
        end;

        if AHit > 0 then
        begin
          Say(IntToStr(AHit) + ' Catalog Label updated.');
        end;
      end;
    finally
      AProps.Free;
      ACheckList.Free;
    end;
  end;

var
  AProps: TCatalogItemProps;
begin
  ChangeList := TTntStringList.Create;
  ConfigForm := BuildForm;
  try
    ConfigForm.PrepareModal([mbOk, mbCancel]);
    ConfigForm.ShowModal;

    if ConfigForm.ModalResult = mrOk then
    begin
      WriteToRegistry('ScriptPlacesHierarchy', 'OffsetLevel', OffsetLevel.Value);
      WriteToRegistry('ScriptPlacesHierarchy', 'CountryMapping', CountryMapping.IsChecked);
      WriteToRegistry('ScriptPlacesHierarchy', 'StateMapping', StateMapping.IsChecked);
      WriteToRegistry('ScriptPlacesHierarchy', 'CityMapping', CityMapping.IsChecked);
      WriteToRegistry('ScriptPlacesHierarchy', 'LocationMapping', LocationMapping.IsChecked);

      AProps := TCatalogItemProps.Create(TCatalogItemProp, '');
      try
        // read first level
        PublicCatalog.EnumPropsForParent(PlacesGUID, AProps, False, False);

        ChangeCount := 0;
        HandlePropsAtLevel(AProps, 1);
      finally
        AProps.Free;
      end;

      if ChangeList.Count > 0 then
        HandleChangeList
      else
        Say('No changes needed');
    end;
  finally
    ConfigForm.Free;
    ChangeList.Free;
  end;
end;