-
-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathSandboxBase.ComboHandlers.cs
More file actions
3384 lines (3098 loc) · 115 KB
/
Copy pathSandboxBase.ComboHandlers.cs
File metadata and controls
3384 lines (3098 loc) · 115 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) 2015-2018 SIL International
// This software is licensed under the LGPL, version 2.1 or later
// (http://www.gnu.org/licenses/lgpl-2.1.html)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using SIL.LCModel.Core.Text;
using SIL.LCModel.Core.WritingSystems;
using SIL.LCModel.Core.KernelInterfaces;
using SIL.FieldWorks.Common.ViewsInterfaces;
using SIL.FieldWorks.Common.FwUtils;
using SIL.FieldWorks.Common.Widgets;
using SIL.LCModel;
using SIL.LCModel.Application;
using SIL.LCModel.DomainServices;
using SIL.LCModel.Infrastructure;
using SIL.FieldWorks.FdoUi;
using SIL.FieldWorks.LexText.Controls;
using SIL.ObjectModel;
using XCore;
using Color=System.Drawing.Color;
namespace SIL.FieldWorks.IText
{
/// <summary>
/// An interface common to classes that 'handle' combo boxes that appear when something in
/// IText is clicked.
/// </summary>
internal interface IComboHandler : IDisposable
{
/// <summary>
/// Initialize the combo contents.
/// </summary>
void SetupCombo();
/// <summary>
/// Get rid of the combo, typically when the user clicks outside it.
/// </summary>
void Hide();
/// <summary>
/// Handle a return key press in an editable combo.
/// </summary>
/// <returns></returns>
bool HandleReturnKey();
/// <summary>
/// Activate the combo-handler's control.
/// If the control is a combo make it visible at the indicated location.
/// If it is a ComboListBox pop it up at the relevant place for the indicated location.
/// </summary>
/// <param name="loc"></param>
void Activate(Rect loc);
/// <summary>
/// This one is a bit awkward in this interface, but it simplifies things. It's OK to
/// just answer zero if the handler has no particular morpheme selected.
/// </summary>
int SelectedMorphHvo { get; }
/// <summary>
/// Act as if the user selected the current item.
/// </summary>
void HandleSelectIfActive();
}
partial class SandboxBase
{
/// <summary>
/// This class and its subclasses handles the events that can happen in the course of
/// the use of a combo box or popup list box in the Sandbox. Actually, a collection of
/// subclasses, one for each kind of place the combo can be in the annotation hierarchy,
/// handles the events. For most of the primary events, the default here is to do
/// nothing.
/// </summary>
public class InterlinComboHandler : DisposableBase, IComboHandler
{
// Main array of information retrieved from sel that made combo.
protected SelLevInfo[] m_rgvsli;
protected int m_hvoSbWord; // Hvo of the root word.
protected int m_hvoSelObject; // lowest level object selected.
// selected morph, if any...may be zero if not in morph, or equal to m_hvoSelObject.
protected int m_hvoMorph;
// int for all classes, except IhMissingEntry, which studds MorphItem data into it.
// So, that ill-behaved class has to make its own m_items data member.
protected List<int> m_items = new List<int>();
private IComboList m_comboList;
// More parallel data for the comboList items.
protected IVwRootBox m_rootb;
protected int m_wsVern; // HVO of default vernacular writing system.
protected int m_wsAnal;
protected int m_wsUser;
protected CachePair m_caches;
protected bool m_fUnderConstruction; // True during SetupCombo.
protected SandboxBase m_sandbox; // the sandbox we're manipulating.
public InterlinComboHandler()
: base()
{
}
internal InterlinComboHandler(SandboxBase sandbox)
: this()
{
m_sandbox = sandbox;
m_caches = sandbox.Caches;
m_wsVern = m_sandbox.RawWordformWs;
m_wsAnal = m_caches.MainCache.DefaultAnalWs;
m_wsUser = m_caches.MainCache.DefaultUserWs;
m_hvoSbWord = kSbWord;
m_rootb = sandbox.RootBox;
}
internal bool IsParsingDevMode()
{
if (m_sandbox.InterlinDoc?.GetMaster() == null)
return false;
return m_sandbox.InterlinDoc.GetMaster().IsParsingDevMode();
}
// only for testing
internal void SetSandboxForTesting(SandboxBase sandbox)
{
m_sandbox = sandbox;
m_caches = sandbox.Caches;
m_wsVern = m_caches.MainCache.DefaultVernWs;
}
internal void SetComboListForTesting(IComboList list)
{
m_comboList = list;
}
internal void SetMorphForTesting(int imorph)
{
m_hvoMorph = m_sandbox.Caches.DataAccess.get_VecItem(kSbWord, ktagSbWordMorphs, imorph);
}
#region DisposableBase for IDisposable
protected override void DisposeManagedResources()
{
// Dispose managed resources here.
if (m_comboList != null && (m_comboList is IDisposable) && (m_comboList as Control).Parent == null)
(m_comboList as IDisposable).Dispose();
else if (m_comboList is ComboListBox)
{
// It typically has a parent, the special form used to display it, so will not
// get disposed by the above, but we do want to dispose it.
(m_comboList as IDisposable).Dispose();
}
if (m_items != null)
m_items.Clear(); // I've seen it contain ints or MorphItems.
}
protected override void DisposeUnmanagedResources()
{
// Dispose unmanaged resources here, whether disposing is true or false.
m_rgvsli = null;
m_caches = null;
m_sandbox = null;
m_rootb = null;
m_items = null;
m_comboList = null;
}
protected override void Dispose(bool disposing)
{
Debug.WriteLineIf(!disposing, "****** Missing Dispose() call for " + GetType().Name + " ******");
base.Dispose(disposing);
}
#endregion DisposableBase for IDisposable
/// <summary>
/// encapsulates the common behavior of items in an InterlinComboHandler combo list.
/// </summary>
internal class InterlinComboHandlerActionComboItem : HvoTssComboItem
{
EventHandler OnSelect;
/// <summary>
///
/// </summary>
/// <param name="tssDisplay">the tss used to display the text of the combo item.</param>
/// <param name="select">the event delegate to be executed when this item is selected. By default,
/// we send "this" InterlinComboHandlerActionComboItem as the event sender.</param>
internal InterlinComboHandlerActionComboItem(ITsString tssDisplay, EventHandler select)
: this(tssDisplay, select, 0, 0)
{
}
/// <summary>
///
/// </summary>
/// <param name="tssDisplay">the tss to display in the combo box.</param>
/// <param name="select">the event to fire when this is selected</param>
/// <param name="hvoPrimary">the hvo most closely associated with this item, 0 if none.</param>
/// <param name="tag">id to resolve any further ambiguity associated with this item's hvo.</param>
internal InterlinComboHandlerActionComboItem(ITsString tssDisplay, EventHandler select, int hvoPrimary, int tag)
: base(hvoPrimary, tssDisplay, tag)
{
OnSelect = select;
}
/// <summary>
/// If enabled, will do something if clicked.
/// </summary>
internal bool IsEnabled
{
get { return OnSelect != null; }
}
/// <summary>
/// Do OnSelect if defined, and this item is enabled.
/// By default, we send "this" InterlinComboHandlerActionComboItem as the event sender.
/// </summary>
internal protected virtual void OnSelectItem()
{
if (OnSelect != null && IsEnabled)
OnSelect(this, EventArgs.Empty);
}
}
/// <summary>
/// Setup the properties for combo items that should appear disabled.
/// </summary>
/// <returns></returns>
protected static ITsTextProps DisabledItemProperties()
{
return HighlightProperty(Color.LightGray);
}
/// <summary>
/// Setup a property for a specified color.
/// </summary>
/// <returns></returns>
protected static ITsTextProps HighlightProperty(System.Drawing.Color highlightColor)
{
int color = (int)CmObjectUi.RGB(highlightColor);
ITsPropsBldr bldr = TsStringUtils.MakePropsBldr();
bldr.SetIntPropValues((int)FwTextPropType.ktptForeColor,
(int)FwTextPropVar.ktpvDefault, color);
return bldr.GetTextProps();
}
// Call this to create the appropriate subclass and set up the combo and return it.
// May return null if no appropriate combo can be created at the current position.
// Caller should hide all combos before calling, then
// call Activate to add the combo to its controls (thus making it visible)
// or display the ComboListBox if a non-null value
// is returned.
static internal IComboHandler MakeCombo(IHelpTopicProvider helpTopicProvider,
IVwSelection vwselNew, SandboxBase sandbox, bool fMouseDown)
{
if (!vwselNew.IsValid)
throw new ArgumentException("The selection is invalid.", "vwselNew");
// Figure what property is selected and create a suitable class if appropriate.
int cvsli = vwselNew.CLevels(false);
// CLevels includes the string property itself, but AllTextSelInfo doesn't need
// it.
cvsli--;
// Out variables for AllTextSelInfo.
int ihvoRoot;
int tagTextProp;
int cpropPrevious;
int ichAnchor;
int ichEnd;
int ws;
bool fAssocPrev;
int ihvoEnd;
ITsTextProps ttpBogus;
// Main array of information retrived from sel that made combo.
SelLevInfo[] rgvsli;
// Analysis can now be zero (e.g., displaying alterate case form for non-existent WfiWordform)
// and I don't believe it's a problem for the code below (JohnT).
// if (sandbox.Analysis == 0)
// {
// // We aren't fully initialized yet, so don't do anything.
// return null;
// }
if (cvsli < 0)
return null;
try
{
rgvsli = SelLevInfo.AllTextSelInfo(vwselNew, cvsli,
out ihvoRoot, out tagTextProp, out cpropPrevious, out ichAnchor, out ichEnd,
out ws, out fAssocPrev, out ihvoEnd, out ttpBogus);
}
catch
{
// If anything goes wrong just give up.
return null;
}
int hvoMorph = 0;
int hvoSelObject = 0;
if (tagTextProp >= ktagMinIcon && tagTextProp < ktagLimIcon) // its an icon
{
// If we're just hovering don't launch the pull-down.
if (!fMouseDown)
return null;
if (rgvsli.Length >= 1)
hvoMorph = hvoSelObject = rgvsli[0].hvo;
return MakeCombo(helpTopicProvider, tagTextProp, sandbox, hvoMorph, rgvsli, hvoSelObject);
}
return null;
}
/// --------------------------------------------------------------------------------
/// <summary>
/// make a combo handler based upon the given comboIcon and morph
/// </summary>
/// <param name="helpTopicProvider">The help topic provider.</param>
/// <param name="tagComboIcon">The tag combo icon.</param>
/// <param name="sandbox">The sandbox.</param>
/// <param name="imorph">The index of the morph.</param>
/// <returns></returns>
/// --------------------------------------------------------------------------------
internal static IComboHandler MakeCombo(IHelpTopicProvider helpTopicProvider,
int tagComboIcon, SandboxBase sandbox, int imorph)
{
int hvoSbMorph = sandbox.Caches.DataAccess.get_VecItem(kSbWord, ktagSbWordMorphs, imorph);
return MakeCombo(helpTopicProvider, tagComboIcon, sandbox, hvoSbMorph, null, 0);
}
private static IComboHandler MakeCombo(IHelpTopicProvider helpTopicProvider,
int tagComboIcon, SandboxBase sandbox, int hvoMorph, SelLevInfo[] rgvsli, int hvoSelObject)
{
IVwRootBox rootb = sandbox.RootBox;
int hvoSbWord = sandbox.RootWordHvo;
InterlinComboHandler handler = null;
CachePair caches = sandbox.Caches;
switch (tagComboIcon)
{
case ktagMorphFormIcon:
handler = new IhMorphForm();
break;
case ktagMorphEntryIcon:
handler = new IhMorphEntry(helpTopicProvider);
break;
case ktagWordPosIcon:
handler = new IhWordPos();
break;
case ktagAnalysisIcon:
ComboListBox clb2 = new ComboListBox();
clb2.StyleSheet = sandbox.StyleSheet;
ChooseAnalysisHandler caHandler = new ChooseAnalysisHandler(
caches.MainCache, hvoSbWord, sandbox.Analysis, sandbox.m_occurrenceSelected, clb2);
caHandler.Owner = sandbox;
caHandler.AnalysisChosen += new EventHandler(
sandbox.Handle_AnalysisChosen);
caHandler.SetupCombo();
return caHandler;
case ktagWordGlossIcon: // line 6, word gloss.
if (sandbox.ShouldAddWordGlossToLexicon)
{
if (hvoMorph == 0)
{
// setup the first hvoMorph
hvoMorph = caches.DataAccess.get_VecItem(kSbWord, ktagSbWordMorphs, 0);
}
handler = new IhLexWordGloss(helpTopicProvider);
}
else
{
handler = new IhWordGloss();
}
break;
default:
return null;
}
// Use the base class handler for most handlers. Override where needed.
if (!(handler is IhWordPos))
{
ComboListBox clb = new ComboListBox();
handler.m_comboList = clb;
clb.SelectedIndexChanged += new EventHandler(
handler.HandleComboSelChange);
clb.SameItemSelected += new EventHandler(
handler.HandleComboSelSame);
// Since we may initialize with TsStrings, need to set WSF.
handler.m_comboList.WritingSystemFactory =
caches.MainCache.LanguageWritingSystemFactoryAccessor;
}
else
{
// REVIEW: Do we need to handle wsf for word POS combo?
}
handler.m_caches = caches;
handler.m_hvoSelObject = hvoSelObject;
handler.m_hvoSbWord = hvoSbWord;
handler.m_hvoMorph = hvoMorph;
handler.m_rgvsli = rgvsli;
handler.m_rootb = rootb;
handler.m_wsVern = sandbox.RawWordformWs;
handler.m_wsAnal = caches.MainCache.DefaultAnalWs;
handler.m_wsUser = caches.MainCache.DefaultUserWs;
handler.m_sandbox = sandbox;
handler.m_fUnderConstruction = true;
handler.SetupCombo();
if (handler.m_comboList != null)
handler.m_comboList.StyleSheet = sandbox.StyleSheet;
handler.m_fUnderConstruction = false;
return handler;
}
private void ComboListHidden(object sender, EventArgs args)
{
if (!(sender is ComboListBox))
{
throw new ApplicationException("Unexpected origin of ComboListHidden event.");
}
((ComboListBox)sender).FormHidden -= ComboListHidden;
if (m_sandbox != null && !m_sandbox.IsDisposed)
{
m_sandbox.Focus();
}
}
/// <summary>
/// Hide yourself.
/// </summary>
public void Hide()
{
CheckDisposed();
HideCombo();
}
// If the handler is managing a combo box and it is visible hide it.
// Likewise if it is a combo list.
internal void HideCombo()
{
CheckDisposed();
ComboListBox clb = m_comboList as ComboListBox;
if (clb != null)
{
if (clb.IsDisposed)
{
// This can happen if the user tries hard enough. See FWR-3577.
// It seems to get reconstructed okay if we just clear it.
m_comboList = null;
}
else
{
clb.HideForm();
}
}
}
// Activate the combo-handler's control.
// If the control is a combo make it visible at the indicated location.
// If it is a ComboListBox pop it up at the relevant place for the indicated
// location.
public virtual void Activate(Rect loc)
{
CheckDisposed();
AdjustListBoxSize();
ComboListBox c = (m_comboList as ComboListBox);
c.AdjustSize(500, 400); // these are maximums!
c.FormHidden += ComboListHidden;
c.Launch(m_sandbox.RectangleToScreen(loc),
Screen.GetWorkingArea(m_sandbox));
}
internal void AdjustListBoxSize()
{
CheckDisposed();
if (m_comboList is ComboListBox)
{
ComboListBox clb = m_comboList as ComboListBox;
using (var g = m_sandbox.CreateGraphics())
{
int nMaxWidth = 0;
int nHeight = 0;
IEnumerator ie = clb.Items.GetEnumerator();
while (ie.MoveNext())
{
string s = null;
if (ie.Current is ITsString)
{
ITsString tss = ie.Current as ITsString;
s = tss.Text;
}
else if (ie.Current is String)
{
s = ie.Current as string;
}
if (s != null)
{
SizeF szf = g.MeasureString(s, clb.Font);
int nWidth = (int)szf.Width + 2;
if (nMaxWidth < nWidth)
// 2 is not quite enough for height if you have homograph
// subscripts.
nMaxWidth = nWidth;
nHeight += (int)szf.Height + 3;
}
}
clb.Form.Width = Math.Max(clb.Form.Width, nMaxWidth);
clb.Form.Height = Math.Max(clb.Form.Height, nHeight);
}
}
}
public int SelectedMorphHvo
{
get
{
CheckDisposed();
return m_hvoMorph;
}
}
// Return true if handled, otherwise, default behavior.
public virtual bool HandleReturnKey()
{
CheckDisposed();
return false;
}
// Handles a change in the item selected in the combo box.
// Sub-classes can override where needed.
internal virtual void HandleComboSelChange(object sender, EventArgs ea)
{
CheckDisposed();
// Revisit (EricP): we could reimplement m_sandbox.HandleComboSelChange
// here, but I suppose duplicating the logic here isn't necessary.
// For now just use that one.
// Assuming it's not disposed, which it might be apparently on switching tools.
// (See LT-12350)
if (!m_sandbox.IsDisposed)
{
m_sandbox.HandleComboSelChange(sender, ea);
}
// Alternative re-implementation:
// if (m_fUnderConstruction)
// return;
// this.HideCombo();
// HandleSelectIfActive();
}
// Handles an item in the combo box when it is the same.
// Sub-classes can override where needed.
internal virtual void HandleComboSelSame(object sender, EventArgs ea)
{
CheckDisposed();
// by default, just do the same as when item selected has changed.
this.HandleComboSelChange(sender, ea);
}
/// <summary>
/// Handle the user selecting an item in the control.
/// </summary>
public virtual void HandleSelectIfActive()
{
CheckDisposed();
if (!m_fUnderConstruction)
HandleSelect(m_comboList.SelectedIndex);
if (m_sandbox.ParentForm == Form.ActiveForm)
m_sandbox.Focus();
}
// Handle the user selecting an item in the combo box.
// Todo JohnT: many of the overrides should probably create a new selection.
// The caller first hides the combo, so it can be manipulated in various
// ways and possibly shown in a new place. Method should redisplay it if
// appropriate.
public virtual void HandleSelect(int index)
{
CheckDisposed();
}
/// <summary>
/// select the combo list item matching the given string
/// </summary>
/// <param name="target"></param>
public virtual void SelectComboItem(string target)
{
int index;
object foundItem = GetComboItem(target, out index);
if (foundItem != null)
{
HandleSelect(index);
}
}
internal object GetComboItem(string target, out int index)
{
object foundItem = null;
index = 0;
if (m_comboList != null)
{
foreach (object item in m_comboList.Items)
{
if (((item is ITsString) && (item as ITsString).Text == target) ||
(item is ITssValue) && (item as ITssValue).AsTss.Text == target)
{
foundItem = item;
break;
}
else if (item.Equals(target))
{
foundItem = item;
break;
}
index++;
}
}
else if (Items != null)
{
// if Items is a list of Possibility hvos, you can check against names.
foreach (int hvo in Items)
{
ICmPossibility possibility =
m_caches.MainCache.ServiceLocator.GetInstance<ICmPossibilityRepository>().GetObject(hvo);
if (possibility != null && possibility.Name.BestAnalysisVernacularAlternative.Text == target)
{
foundItem = hvo;
break;
}
index++;
}
}
return foundItem;
}
/// <summary>
/// select the combo item matching the given hvoTarget
/// </summary>
/// <param name="hvoTarget"></param>
public virtual void SelectComboItem(int hvoTarget)
{
int index = 0;
foreach (int item in Items)
{
if (item == hvoTarget)
{
HandleSelect(index);
break;
}
index++;
}
}
// This method contains the default SetupCombo functions, for the benefit of
// classes that need to override without calling the immediate superclass,
// but do want the general default behavior.
internal void InitCombo()
{
CheckDisposed();
m_items.Clear();
m_comboList.Items.Clear();
// Some SetupCombo methods alter this to DropDownList, which prevents editing,
// but it's useful to have a set default. Note that this needs to be done each
// time, because we reuse the combo, and changes in one location can affect others.
m_comboList.DropDownStyle = ComboBoxStyle.DropDown;
}
/// <summary>
/// Return the index of the currently selected item. Subclasses can override this
/// method for finding the sandbox setting, so it can select and highlight
/// that item in the list, rather than the default.
/// </summary>
/// <returns></returns>
public virtual int IndexOfCurrentItem
{
get
{
if (m_comboList != null)
return m_comboList.SelectedIndex;
return -1;
}
}
// Save extra information needed for other commands, and set the combo items.
// Or, change m_comboList to a new ComboListBox. This will result in no combo box
// being displayed.
public virtual void SetupCombo()
{
CheckDisposed();
InitCombo();
}
/// <summary>
/// the hvos related to the parallel items in m_comboList.Items
/// </summary>
public virtual List<int> Items
{
get { return m_items; }
}
/// <summary>
/// Handles the problem that an ITsString returns null (which works fine as a BSTR) when there
/// are no characters. But in C#, null is not the same as an empty string.
/// Also handles the possibility that the ITsString itself is null.
/// </summary>
/// <param name="tss"></param>
/// <returns></returns>
public static string StrFromTss(ITsString tss)
{
if (tss == null)
return string.Empty;
string result = tss.Text;
if (result != null)
return result;
return string.Empty;
}
// Change the selection, keeping the higher levels of the current spec
// from isliCopy onwards, and adding a new lowest level that has
// cpropPrevious 0, and the specified tag and ihvo.
// The selection made is an IP at the start of the property tagTextProp,
// writing system ws, of the object thus specified.
// (The selection is in the first and usually only root object.)
internal void MakeNewSelection(int isliCopy, int tag, int ihvo, int tagTextProp, int ws)
{
CheckDisposed();
SelLevInfo[] rgvsli = new SelLevInfo[m_rgvsli.Length - isliCopy + 1];
for (int i = isliCopy; i < m_rgvsli.Length; i++)
rgvsli[i - isliCopy + 1] = m_rgvsli[i];
rgvsli[0].cpropPrevious = 0;
rgvsli[0].ihvo = ihvo;
rgvsli[0].tag = tag;
// first and only root object; length and array of path to target object;
// property, no previous occurrences, range 0 to 0, no ws, not assocPrev,
// no other object for the other end,
// no override text props, do make it the current active selection.
m_rootb.MakeTextSelection(0, rgvsli.Length, rgvsli, tagTextProp,
0, 0, 0, ws, false, -1, null, true);
}
/// <summary>
/// Add to the combo list the items in property flidVec of object hvoOwner in the main cache.
/// Add to m_comboList.items the ShortName of each item, and to m_items the hvo.
/// </summary>
/// <param name="hvoOwner"></param>
/// <param name="flidVec"></param>
internal void AddVectorToComboItems(int hvoOwner, int flidVec)
{
CheckDisposed();
ISilDataAccess sda = m_caches.DataAccess;
int citem = sda.get_VecSize(hvoOwner, flidVec);
var coRepository = m_caches.MainCache.ServiceLocator.GetInstance<ICmObjectRepository>();
for (int i = 0; i < citem; i++)
{
int hvoItem = sda.get_VecItem(hvoOwner, flidVec, i);
m_items.Add(hvoItem);
m_comboList.Items.Add(coRepository.GetObject(hvoItem).ShortName);
}
}
internal void AddPartsOfSpeechToComboItems()
{
CheckDisposed();
AddVectorToComboItems(m_caches.MainCache.LangProject.PartsOfSpeechOA.Hvo,
CmPossibilityListTags.kflidPossibilities);
}
internal int MorphCount
{
get
{
CheckDisposed();
return m_sandbox.MorphCount;
}
}
/// <summary>
/// Items that appear in the dropdown control for each interlinear line in the sandbox
/// </summary>
internal IComboList ComboList
{
get { return m_comboList; }
}
internal int MorphHvo(int i)
{
CheckDisposed();
return m_caches.DataAccess.get_VecItem(m_hvoSbWord, ktagSbWordMorphs, i);
}
internal ITsString NewAnalysisString(string str)
{
CheckDisposed();
return TsStringUtils.MakeString(str, m_caches.MainCache.DefaultAnalWs);
}
internal void SyncMonomorphemicGlossAndPos(bool fCopyToWordGloss, bool fCopyToWordPos)
{
CheckDisposed();
m_sandbox.SyncMonomorphemicGlossAndPos(fCopyToWordGloss, fCopyToWordPos);
}
protected virtual void CopySenseToWordGloss(bool fCopyWordGloss, int hvoSbRootSense)
{
m_sandbox.CopySenseToWordGloss(fCopyWordGloss, hvoSbRootSense);
}
protected virtual int CopyLexPosToWordPos(bool fCopyToWordCat, int hvoMsaPos)
{
return m_sandbox.CopyLexPosToWordPos(fCopyToWordCat, hvoMsaPos);
}
}
/// <summary>
/// The actual form of the word. Eventually we will offer a popup representing all the
/// currently known possible analyses, and other options.
/// </summary>
internal class IhSbWordForm : InterlinComboHandler
{
public override void SetupCombo()
{
CheckDisposed();
base.SetupCombo();
ComboList.Items.Add(ITextStrings.ksAcceptEntireAnalysis);
ComboList.Items.Add(ITextStrings.ksEditThisWordform);
ComboList.Items.Add(ITextStrings.ksDeleteThisWordform);
// These aren't likely to get implemented soon.
//m_comboList.Items.Add("Change spelling of occurrences");
//m_comboList.Items.Add("Concordance");
//// following not valid, don't know how in .NET, maybe Add("-")?
//m_comboList.Items.AddSeparator();
//m_comboList.Add("Interlinear help");
ComboList.DropDownStyle = ComboBoxStyle.DropDownList; // Prevents direct editing.
}
public override void HandleSelect(int index)
{
CheckDisposed();
switch (index)
{
case 0: // Accept entire analysis
// Todo: figure how to implement.
break;
case 1: // Edit this wordform.
// Allows direct editing.
ComboList.DropDownStyle = ComboBoxStyle.DropDown;
// restore the combo to visibility so we can do the editing.
m_sandbox.ShowCombo();
break;
case 2: // Delete this wordform.
// Todo: figure implementation
// int ihvoTwfic = m_rgvsli[m_iRoot].ihvo;
// int [] itemsToInsert = new int[0];
// m_cache.ReplaceReferenceProperty(m_hvoSbWord,
// StTxtParaTags.kflidAnalyzedTextObjects,
// ihvoTwfic, ihvoTwfic + 1, ref itemsToInsert);
// Enhance JohnT: consider removing the WfiWordform, if there are no
// analyses and no other references.
// Comment: RandyR: Please don't delete it.
break;
}
}
public override bool HandleReturnKey()
{
CheckDisposed();
// If it hasn't changed don't do anything.
string newval = ComboList.Text;
if (newval == StrFromTss(m_caches.DataAccess.get_MultiStringAlt(m_hvoSbWord, ktagSbWordForm, m_sandbox.RawWordformWs)))
{
return true;
}
// Todo JohnT: clean out old analysis, come up with new defaults.
//SetAnalysisTo(DbOps.FindOrCreateWordform(m_cache, tssWord));
// Enhance JohnT: consider removing the old WfiWordform, if there are no
// analyses and no other references.
return true;
}
}
internal class IhMorphForm : InterlinComboHandler
{
internal IhMorphForm()
: base()
{
}
internal IhMorphForm(SandboxBase sandbox)
: base(sandbox)
{
}
public override int IndexOfCurrentItem
{
get
{
return 0; // Treat the first item as the selected item.
}
}
public override void SetupCombo()
{
CheckDisposed();
base.SetupCombo();
// Any time we pop this up, the text in the box is the text form of the current
// analysis, as a starting point.
ITsStrBldr builder = TsStringUtils.MakeStrBldr();
int cmorphs = MorphCount;
Debug.Assert(cmorphs != 0); // we're supposed to be building on one of them!
var wordform = m_sandbox.GetWordformOfAnalysis();
IWfiAnalysis wa = m_sandbox.GetWfiAnalysisInUse();
// Find the actual original form of the current wordform
ITsString tssForm = m_sandbox.FindAFullWordForm(wordform);
string form = StrFromTss(tssForm);
bool fBaseWordIsPhrase = SandboxBase.IsPhrase(form);
// First, store the current morph breakdown if we have one,
// Otherwise, if the user has deleted all the morphemes on the morpheme line
// (per LT-1621) simply use the original wordform.
// NOTE: Normally we would use Sandbox.IsMorphFormLineEmpty for this condition
// but since we're already using the variable(s) needed for this check,
// here we'll use those variables for economy/performance instead.
string currentBreakdown = m_sandbox.SandboxEditMonitor.BuildCurrentMorphsString();
if (currentBreakdown != string.Empty)
{
ComboList.Text = currentBreakdown;
// The above and every other distinct morpheme breakdown from owned
// WfiAnalyses are possible choices.
ITsString tssText = TsStringUtils.MakeString(currentBreakdown, m_wsVern);
ComboList.Items.Add(tssText);
}
else
{
ComboList.Text = form;
ComboList.Items.Add(tssForm);
}
// if we added the fullWordform (or the current breakdown is somehow empty although we may have an analysis), then add the
// wordform HVO; otherwise, add the analysis HVO.
if (currentBreakdown == string.Empty || (wa == null && tssForm != null && tssForm.Equals(ComboList.Items[0] as ITsString)))
m_items.Add(wordform != null ? wordform.Hvo : 0);
else
m_items.Add(wa != null ? wa.Hvo : 0); // [wfi] hvoAnalysis may equal '0' (for annotations that are instances of Wordform).
Debug.Assert(m_items.Count == ComboList.Items.Count,
"combo list (m_comboList) should contain the same count as the m_items list (hvos)");
AddAnalysesOf(wordform, fBaseWordIsPhrase);
// Add the original wordform, if not already present.
AddIfNotPresent(tssForm, wordform);
ComboList.SelectedIndex = this.IndexOfCurrentItem;
// Add any relevant 'other case' forms.
var wsVern = m_caches.MainCache.ServiceLocator.WritingSystemManager.Get(m_sandbox.RawWordformWs);
CaseFunctions cf = new CaseFunctions(wsVern);
switch (m_sandbox.CaseStatus)
{
case StringCaseStatus.allLower:
break; // no more to add
case StringCaseStatus.title:
AddOtherCase(cf.SwitchTitleAndLower(form));
break;
case StringCaseStatus.mixed:
switch (cf.StringCase(form))
{
case StringCaseStatus.allLower:
AddOtherCase(cf.ToTitle(form));
AddOtherCase(m_sandbox.RawWordform.Text);
break;
case StringCaseStatus.title:
AddOtherCase(cf.ToLower(form));
AddOtherCase(m_sandbox.RawWordform.Text);
break;
case StringCaseStatus.mixed:
AddOtherCase(cf.ToLower(form));
AddOtherCase(cf.ToTitle(form));
break;