-
Notifications
You must be signed in to change notification settings - Fork 3
/
VB.xojo_code
1412 lines (1185 loc) · 44.5 KB
/
VB.xojo_code
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
#tag Module
Protected Module VB
#tag Method, Flags = &h1
Protected Sub AppActivate(title As String, unused As Boolean = False)
// We want to activate an "application" based on the
// window title, or partial window title. From the VB6 docs:
//
// In determining which application to activate, title is compared to the title
// string of each running application. If there is no exact match, any application
// whose title string begins with title is activated. If there is more than one
// instance of the application named by title, one instance is arbitrarily activated.
//
// The way I interpret this is that we should loop over all the processes
// and look at the name. If the name is an exact match, then we use
// that one. If no matches are found, we go back and look at the
// beginning of the each process name to see if we can find a match. If
// we still can't find one, then I think we're supposed search window titles
// in the same fashion. It's ambiguous though. The parameter specifier
// from the same docs says: "...the title in the title bar of the application window you
// want to activate..." So which is it -- process name or window title?
//
// Turns out that the answer is "exact window title", as learned from
// http://support.microsoft.com/kb/q147659/
//
// "The Visual Basic AppActivate command can only activate a window if
// you know the exact window title. Similarly, the Windows FindWindow
// function can only find a window handle if you know the exact window title. "
#If TargetWin32
Soft Declare Function FindWindowA Lib "User32" (className As Integer, title As CString) As Integer
Soft Declare Function FindWindowW Lib "User32" (className As Integer, title As WString) As Integer
// Find the window via an exact match using FindWindow
Dim handle As Integer
If System.IsFunctionAvailable("FindWindowW", "User32") Then
handle = FindWindowW(0, title)
Else
handle = FindWindowA(0, title)
End If
// If we found a handle, then we want to bring it to the front
If handle <> 0 Then
Declare Sub SetForegroundWindow Lib "User32" (hwnd As Integer)
SetForegroundWindow(handle)
End If
#EndIf
End Sub
#tag EndMethod
#tag Method, Flags = &h21
Private Function ASCIIToScanKey(char As String) As Integer
#If TargetWin32
Declare Function VkKeyScanA Lib "User32" (ch As Integer) As Int16
Dim theAscVal As Integer = Asc(char)
Return VkKeyScanA(theAscVal)
#EndIf
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function ATn(d As Double) As Double
Return ATan(d)
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub ChDir(path As Text)
#If TargetWin32
Soft Declare Function SetCurrentDirectoryW Lib "Kernel32" (dir As WString) As Boolean
Call SetCurrentDirectoryW(path)
#Endif
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub ChDrive(letter As Text)
// We only want to look at the first character, so let's
// ensure that we have only one.
#If TargetWindows
letter = letter.Left(1)
// If the letter is empty, we can bail out
If letter = "" Then Return
// Now we want to change the drive. We can
// do this with ChDir.
ChDir(letter + ":\")
#Endif
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Command() As Text
// This should return just the command line part after the file
// name. It returns it without parsing it. In Xojo, the
// command line comes with the filename, so we need to parse
// that out.
// Get the entire command line
Dim commandLine As String = System.CommandLine
// Let the helper function deal with the hard stuff
Dim temp As String
Return GetParams(commandLine, temp).ToText
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function CurDir() As Text
// The user just wants the path to the current directory
Return GetCurrentDirectory.NativePath.ToText
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Date() As Text
// Get the current long date as text
Return Xojo.Core.Date.Now.ToText(Xojo.Core.Locale.Current, _
Xojo.Core.Date.FormatStyles.Long, Xojo.Core.Date.FormatStyles.None)
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Day() As Integer
// Returns the day of the month for the current date
Return Xojo.Core.Date.Now.Day
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub DeleteSetting(appName As String, section As String, key As String = "")
#If TargetWindows
// First, we want to get a registry key that points
// to the default location of all VB settings.
Dim base As New RegistryItem(kSettingsLocation)
// Now we want to delve into the appName folder
base = base.Child(appName)
// If we don't have a key name, then we want to
// delete the entire section. Otherwise, we want
// to delve into the section and delete the
// key specified.
If key = "" Then
base.Delete(section)
Else
// Dive into the section
base = base.Child(section)
// And delete the key
base.Delete(key)
End If
Exception err As RegistryAccessErrorException
// Something bad happened, so let's just bail out
Return
#Endif
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub FileCopy(source As Text, dest As Text)
Dim sourceItem As New Xojo.IO.FolderItem(source)
Dim destItem As New Xojo.IO.FolderItem(dest)
// Copy the source to the dest
Try
sourceItem.CopyTo(destItem)
Catch e As IOException
Return
End Try
End Sub
#tag EndMethod
#tag Method, Flags = &h21
Private Sub FillKeyMap(ByRef map As Dictionary)
map.Value("BACKSPACE") = &h8
map.Value("BS") = &h8
map.Value("BKSP") = &h8
map.Value("BREAK") = &h3
map.Value("CAPSLOCK") = &h14
map.Value("DELETE") = &h2E
map.Value("DEL") = &h2E
map.Value("DOWN") = &h28
map.Value("END") = &h23
map.Value("ENTER") = &h0D
map.Value("ESC") = &h1B
map.Value("HELP") = &h2F
map.Value("HOME") = &h24
map.Value("INSERT") = &h2D
map.Value("INS") = &h2D
map.Value("LEFT") = &h25
map.Value("NUMLOCK") = &h90
map.Value("PGDN") = &h22
map.Value("PGUP") = &h21
map.Value("PRTSC") = &h2C
map.Value("RIGHT") = &h27
map.Value("SCROLLLOCK") = &h91
map.Value("TAB") = &h09
map.Value("UP") = &h26
map.Value("+") = ASCIIToScanKey("+")
map.Value("^") = ASCIIToScanKey("^")
map.Value("%") = ASCIIToScanKey("%")
map.Value("~") = ASCIIToScanKey("~")
map.Value("(") = ASCIIToScanKey("(")
map.Value(")") = ASCIIToScanKey(")")
map.Value("{") = ASCIIToScanKey("{")
map.Value("}") = ASCIIToScanKey("}")
map.Value("[") = ASCIIToScanKey("[")
map.Value("]") = ASCIIToScanKey("]")
For i As Integer = 1 To 16
map.Value("F" + Str(i)) = &h70 + (i - 1)
Next i
End Sub
#tag EndMethod
#tag Method, Flags = &h21
Private Function FillString(char As String, numChars As Integer) As String
#If TargetWin32
Declare Sub memset Lib "msvcrt" (dest As Ptr, char As Integer, count As Integer)
Dim mb As New MemoryBlock(LenB( char ) * numChars)
memset(mb, AscB(char), numChars)
Return DefineEncoding(mb, Encoding(char))
#EndIf
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Filter(source() As String, match As String, include As Boolean = True, compare As Integer = 1) As String()
// We want to filter the entries from source which match the match
// string. The include flag says whether we want to return entries
// which do match, or which don't match. The compare flag says
// what type of comparison to use.
Dim ret(-1) As String
For Each s As String In source
Dim add As Boolean
Select Case compare
Case 0, 1 // Binary or text comparison
If StrComp(s, match, compare) = 0 Then add = True
Else
If s = match Then add = True
End Select
// If we're doing exclusion, then add means
// we don't want to add it
If Not include And add Then add = False
// If we want to add it, then do it
If add Then ret.Append(s)
Next s
// Return the results
Return ret
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Fix(num As Double) As Integer
// This function returns the integer portion of the number passed.
// If the number is negative, Fix returns the first negative integer
// greater than or equal to the number. For example, Fix converts -8.4
// to -8. If you want -9, then you should be using Int instead.
Return Sgn(num) * Int(Abs(num))
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function FV(rate As Double, nper As Integer, pmt As Double, pv As Double = 0, type As Integer = 0) As Double
// These equations come from gnucash
// http://www.gnucash.org/docs/v1.8/C/gnucash-guide/loans_calcs1.html
Dim a As Double = (1 + rate) ^ nper - 1
Dim b As Double = (1 + rate * type) / rate
Dim c As Double = pmt * b
Return -(pv + a * (pv + c))
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function GetAllSettings(appName As String, section As String) As Dictionary
#If TargetWindows
// First, we want to get to the default location for all VB apps
Dim base As New RegistryItem(kSettingsLocation)
// Then we want to dive into the app and section folders
base = base.Child(appName).Child(section)
// Loop over all the children and return their values
Dim i, count As Integer
Dim ret As New Dictionary
// How many keys do we have?
count = base.KeyCount
For i = 0 To count - 1
// Grab the key and value and add it to the dictionary
ret.Value(base.Name(i)) = base.Value(i)
Next i
// Return our list
Return ret
Exception err As RegistryAccessErrorException
// Just bail out
Return Nil
#Endif
End Function
#tag EndMethod
#tag Method, Flags = &h21
Private Function GetCurrentDirectory() As FolderItem
#If TargetWin32
Soft Declare Sub GetCurrentDirectoryA Lib "Kernel32" (Len As Integer, buf As Ptr)
Soft Declare Sub GetCurrentDirectoryW Lib "Kernel32" (Len As Integer, buf As Ptr)
Dim path As String
Dim buf As New MemoryBlock(520)
If System.IsFunctionAvailable("GetCurrentDirectoryW", "Kernel32") Then
GetCurrentDirectoryW(buf.Size, buf)
path = buf.WString(0)
Else
GetCurrentDirectoryA(buf.Size, buf)
path = buf.CString(0)
End If
Return New FolderItem(path, FolderItem.PathTypeAbsolute)
#EndIf
Exception err As UnsupportedFormatException
Return Nil
End Function
#tag EndMethod
#tag Method, Flags = &h21
Private Function GetParams(commandLine As String, ByRef file As String) As String
// Now parse the command line so that we can get just what
// is after the application name. We have to do this one
// character at a time, unfortunately
Dim length As Integer = Len(commandLine)
Dim ignoreSpaces As Boolean = False
For curPos As Integer = 1 To length
Dim char As String = Mid(commandLine, curPos, 1)
If char = """" Then
// We found a quote, so we can ignore any spaces. If
// this is the second quote, then we can pay attention
// to spaces again.
ignoreSpaces = Not ignoreSpaces
ElseIf Not ignoreSpaces And (char = " " Or char = Chr(9)) Then
// We have a space. If we're ignoring spaces, then
// it doesn't matter. But if we're not, then we've found
// the end of the application name
file = Trim(Left(commandLine, curPos))
Return Trim(Mid(commandLine, curPos))
End If
Next curPos
file = commandLine
Return ""
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function GetSetting(appName As String, section As String, key As String, default As Variant = "") As Variant
#If TargetWindows
// First, we want to get to the default location for all VB apps
Dim base As New RegistryItem(kSettingsLocation)
// Then we want to dive into the app and section folders
base = base.Child(appName).Child(section)
// Now we want to get the value from the key
Return base.Value(key)
Exception err As RegistryAccessErrorException
// Just bail out
Return default
#Endif
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Hour() As Integer
// Return the hour for the current time
Return Xojo.Core.Date.Now.Hour
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function InStrRev(source As String, substr As String, startPos As Integer = 1, compare As Integer = 1) As Integer
If source = "" Then Return 0
If substr.Len = 0 Then Return startPos
// Similar to InStr, but searches backwards from the given position
// (or if startPos = -1, then from the end of the string).
// If substr can't be found, returns 0.
Dim srcLen As Integer
If compare = 0 Then
srcLen = source.LenB
Else
srcLen = source.Len
End If
If startPos > srcLen Then Return 0
// Here's an easy way...
// There may be a faster implementation, but then again, there may not -- it probably
// depends on what you're trying to do.
Dim reversedSource As String = StrReverse(source)
Dim reversedSubstr As String = StrReverse(substr)
Dim reversedPos As Integer
If compare = 0 Then
reversedPos = InStrB(startPos, reversedSource, reversedSubstr)
Else
reversedPos = InStr(startPos, reversedSource, reversedSubstr)
End If
If reversedPos < 1 Then Return 0
If compare = 0 Then
Return srcLen - reversedPos - substr.LenB + 2
Else
Return srcLen - reversedPos - substr.Len + 2
End If
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Int(num As Double) As Integer
// This function returns the integer portion of the number passed.
// If the number is negative, Int returns the first negative integer
// less than or equal to the number. For example, Int converts -8.4
// to -9. If you want -8, then you should be using Fix instead.
Dim i As Integer = num
If num > 0 Then
Return i
Else
Return i - 1
End If
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function IPmt(rate As Double, per As Integer, nper As Integer, pv As Double, fv As Double = 0, type As Integer = 0) As Double
// IPmt is the principle for the previous month times the interest rate
// http://www.gnome.org/projects/gnumeric/doc/gnumeric-IPMT.shtml
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function IsObject(v As Variant) As Boolean
// If the variant holds an object, this is true. Also, if
// it holds nil, then it's true as well.
Return v.Type = Variant.TypeObject Or v.Type = Variant.TypeNil
End Function
#tag EndMethod
#tag Method, Flags = &h21
Private Sub KeyDown(virtualKeyCode As Integer, extendedKey As Boolean = False)
#If TargetWin32
Declare Sub keybd_event Lib "User32" (keyCode As Integer, scanCode As Integer, _
flags As Integer, extraData As Integer)
Dim flags As Integer
Const KEYEVENTF_EXTENDEDKEY = &h1
If extendedKey Then
flags = KEYEVENTF_EXTENDEDKEY
End If
' Press the key
keybd_event(virtualKeyCode, 0, flags, 0)
#EndIf
End Sub
#tag EndMethod
#tag Method, Flags = &h21
Private Sub KeyUp(virtualKeyCode As Integer, extendedKey As Boolean = False)
#If TargetWin32
Declare Sub keybd_event Lib "User32" (keyCode As Integer, scanCode As Integer, _
flags As Integer, extraData As Integer)
Dim flags As Integer
Const KEYEVENTF_EXTENDEDKEY = &h1
If extendedKey Then
flags = KEYEVENTF_EXTENDEDKEY
End If
Const KEYEVENTF_KEYUP = &h2
flags = BitwiseOr(flags, KEYEVENTF_KEYUP)
keybd_event(virtualKeyCode, 0, flags, 0)
#EndIf
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub Kill(path As String)
// This deletes files from the disk. Also,
// it supports wildcard characters such as * (for multiple
// characters) and ? (for single characters) as a way to
// specify multiple files.
// We need to use FindFirstFile as a way to find all the
// files that we want to delete. We will come up with a
// list of FolderItems, and then we can just use
// FolderItem.Delete on them.
// Make sure the path points to our current directory as well
Dim curDir As String = GetCurrentDirectory.NativePath
path = curDir + path
Dim toBeDeleted() As FolderItem
#If TargetWin32
Soft Declare Function FindFirstFileA Lib "Kernel32" (name As CString, data As Ptr) As Integer
Soft Declare Function FindFirstFileW Lib "Kernel32" (name As WString, data As Ptr) As Integer
Soft Declare Function FindNextFileA Lib "Kernel32" (handle As Integer, data As Ptr) As Boolean
Soft Declare Function FindNextFileW Lib "Kernel32" (handle As Integer, data As Ptr) As Boolean
Declare Sub FindClose Lib "Kernel32" (handle As Integer)
// Check to see whether we're doing unicode processing or not
Dim isUnicode As Boolean = False
If System.IsFunctionAvailable("FindNextFileW", "Kernel32") Then isUnicode = True
// Get the search handle
Dim searchHandle As Integer
Dim searchData As New MemoryBlock(44 + 520 + 28)
If isUnicode Then
searchHandle = FindFirstFileW(path, searchData)
Else
searchHandle = FindFirstFileA(path, searchData)
End If
// If the search handle is 0, then we know that something's wrong and
// we can bail out
If searchHandle = 0 Then Return
// Loop over all the files and add them to our kill list
Dim done As Boolean
Do
// Add the file to our delete list
Try
If isUnicode Then
toBeDeleted.Append(New FolderItem(curDir + searchData.WString(44), FolderItem.PathTypeNative))
Else
toBeDeleted.Append(New FolderItem(curDir + searchData.CString(44), FolderItem.PathTypeNative))
End If
Catch err As UnsupportedFormatException
// We had an error, but I think we should keep trying.
End Try
// Find the next file in our list
If isUnicode Then
done = Not FindNextFileW(searchHandle, searchData)
Else
done = Not FindNextFileA(searchHandle, searchData)
End If
Loop Until done
// Close the search handle
FindClose(searchHandle)
#EndIf
// Now we can loop over all the files to be deleted
// and delete them
For Each item As FolderItem In toBeDeleted
item.Delete
Next item
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Function LCase(s As String) As String
Return s.Lowercase
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Like(toSearch As String, matchingPattern As String) As Boolean
Static re As RegEx
If re = Nil Then re = New RegEx
// convert Like syntax to RegEx syntax
matchingPattern = matchingPattern.ReplaceAll(".", "\.")
matchingPattern = matchingPattern.ReplaceAll("*", ".*")
matchingPattern = matchingPattern.ReplaceAll("#","\d")
matchingPattern = matchingPattern.ReplaceAll("[!", "[^")
// special replace for "[x]" syntax in Like
re.SearchPattern = "\[(.)\]" // match 1 char in brackets
re.ReplacementPattern = "\\\1"
re.Options.ReplaceAllMatches = True
matchingPattern = re.Replace(matchingPattern)
// special replace for "?"
re.SearchPattern = "(?<!\\)\?"
re.ReplacementPattern = "."
matchingPattern = re.Replace(matchingPattern)
// now set up RegEx
re.SearchPattern = "^" + matchingPattern + "$"
// and see if it matches toSearch
If Nil = re.Search(toSearch) Then
// no match found?
Return False
Else
// it did match
Return True
End If
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub LSet(ByRef dest As String, assigns source As String)
// We want to take the source string and left-align it in the
// destination string. What this essentially does is puts the
// source in the left-hand part of dest, and fills the rest of
// dest with spaces. So:
//
// Dim MyString as String = "0123456789"
// Lset MyString = "<-Left"
//
// Means that MyString contains "<-Left ".
// First, calculate the end length of the destination
Dim destLen As Integer = Len(dest)
Dim sourceLen As Integer = Len(source)
// If the source string is greater than the
// destination, we want to trim the source
// string and just be done
If sourceLen >= destLen Then
dest = Left(source, destLen)
Return
End If
// Otherwise, we're stuck doing it the "hard" way.
// First, assign the source (this would make it left-aligned).
dest = source
// Then calculate how many spaces we need to
// add to fill the rest of the length
Dim numSpaces As Integer = destLen - sourceLen
// Now add the spaces
dest = dest + Space(numSpaces)
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub Mid(ByRef txt As String, startPos As Integer, length As Integer = -1, assigns subStr As String)
// Assign the replacement to the original data
txt = Left(txt, startPos) + Left(subStr, length) + _
Mid(txt, startPos + length + 1)
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Minute() As Integer
// Return the current minute
Return Xojo.Core.Date.Now.Minute
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub MkDir(name As String)
// First, get the current directory
Dim curDir As FolderItem = GetCurrentDirectory
If curDir = Nil Then Return
// Now, we want to make a new directory as a
// child of the current one
Dim newDir As FolderItem = curDir.Child(name)
newDir.CreateAsFolder
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Month() As Integer
// Return the current month
Return Xojo.Core.Date.Now.Month
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub Name(oldPathName As String, newPathName As String)
// This moves and/or renames a file. Sound familiar?
// Check to see whether the old path or the new path
// really are paths. If they're not, we need to use the
// current directory.
Dim oldPathIsAbsolute, newPathIsAbsolute As Boolean
If Mid(oldPathName, 2, 2) = ":\" Or Left(oldPathName, 2) = "//" Then
oldPathIsAbsolute = True
End If
If Mid(newPathName, 2, 2) = ":\" Or Left(newPathName, 2) = "//" Then
newPathIsAbsolute = True
End If
// Now we can get folder items for both the new and the
// old path.
Dim oldPath As FolderItem
If oldPathIsAbsolute Then
oldPath = New FolderItem(oldPathName, FolderItem.PathTypeAbsolute)
Else
oldPath = GetCurrentDirectory.Child(oldPathName)
End If
Dim newPath As FolderItem
If newPathIsAbsolute Then
newPath = New FolderItem(newPathName, FolderItem.PathTypeAbsolute)
Else
newPath = GetCurrentDirectory.Child(newPathName)
End If
// Now we can do a move operation. This will also do a rename if
// the oldPath and the newPath reside in the same directory
oldPath.MoveFileTo(newPath)
Exception err As UnsupportedFormatException
Return
Exception err As NilObjectException
Return
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Now() As Xojo.Core.Date
Return Xojo.Core.Date.Now
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Pmt(rate As Double, nper As Integer, pv As Double, fv As Double = 0, type As Integer = 0) As Double
// These equations come from gnucash
// http://www.gnucash.org/docs/v1.8/C/gnucash-guide/loans_calcs1.html
Dim a As Double = (1 + rate) ^ nper - 1
Dim b As Double = (1 + rate * type) / rate
Return -(fv + pv * (a + 1)) / (a * b)
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function PPmt(rate As Double, per As Integer, nper As Integer, pv As Double, fv As Double = 0, type As Integer = 0) As Double
// PPmt is just the Pmt - IPmt, according to
// http://www.gnome.org/projects/gnumeric/doc/gnumeric-PPMT.shtml
Return Pmt(rate, nper, pv, fv, type) - IPmt(rate, per, nper, pv, fv, type)
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function PV(rate As Double, nper As Integer, pmt As Double, fv As Double = 0, type As Integer = 0) As Double
// These equations come from gnucash
// http://www.gnucash.org/docs/v1.8/C/gnucash-guide/loans_calcs1.html
Dim a As Double = (1 + rate) ^ nper - 1
Dim b As Double = (1 + rate * type) / rate
Dim c As Double = pmt * b
Return -(fv + a * c) / (a + 1)
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Function QBColor(index As Integer) As Integer
Select Case index
Case 0 // Black
Return &h000000
Case 1 // Blue
Return &h800000
Case 2 // Green
Return &h8000
Case 3 // Cyan
Return &h808000
Case 4 // Red
Return &h80
Case 5 // Magenta
Return &h800080
Case 6 // Yellow
Return &h8080
Case 7 // White
Return &hC0C0C0
Case 8 // Gray
Return &h808080
Case 9 // Light blue
Return &hFF0000
Case 10 // Light green
Return &hFF00
Case 11 // Light cyan
Return &hFFFF00
Case 12 // Light red
Return &hFF
Case 13 // Light magenta
Return &hFF00FF
Case 14 // Light yellow
Return &hFFFF
Case 15 // Bright white
Return &hFFFFFF
Else
Return 0
End Select
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub Randomize(seed As Integer = -1)
If seed <> -1 Then
mRnd.Seed = seed
Else
mRnd.Seed = mRnd.Number * &hFFFFFFFF
End If
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Replace(source As String, find As String, rep As String, start As Integer = 1, count As Integer = -1, compare As Integer = 1) As String
// We want to replace the search string a certain number of times
// in the source string. This is different than our Replace function which
// only replaces the first instance and ReplaceAll, which replaces all
// instances.
// Do our santity checks
If source = "" Then Return ""
If find = "" Then Return source
If rep = "" Then Return source
If count = 0 Then Return source
// If the user wants to start farther up the string than at
// the first character, we need to do some wiggling since
// REALbasic doesn't let you do specify a start position for
// the source string in Replace
Dim searchStr As String = Mid(source, start)
'Dim curPos As Integer = 1
If count = -1 Then
// We just want to do a replace all
If compare = 0 Then
searchStr = ReplaceAllB(searchStr, find, rep)
Else
searchStr = ReplaceAll(searchStr, find, rep)
End If
Else
// Now we want to do the replaces over and over again.
While count > 0
If compare = 0 Then
searchStr = ReplaceB(searchStr, find, rep)
Else
searchStr = Replace(searchStr, find, rep)
End If
// We have one less replace to do
count = count - 1
Wend
End If
// Now we're set. The only thing we might have to do
// is reconstitute the original part of the search string if
// start is greater than 1.
If start > 1 Then
Return Left(source, start - 1) + searchStr
Else
Return searchStr
End If
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub RmDir(path as String)
// Check to see if the path is an absolute path, or
// just a local one
Dim itemToDelete As FolderItem
If Mid(path, 2, 2) = ":\" Or Left(path, 2) = "//" Then
itemToDelete = New FolderItem(path, FolderItem.PathTypeNative)
Else
itemToDelete = GetCurrentDirectory.Child(path)
End If
// Then delete the item
itemToDelete.Delete
Exception err As UnsupportedFormatException
Return
Exception err As NilObjectException
Return
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Rnd() As Double
Return mRnd.Number
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub RSet(ByRef dest As String, assigns source As String)
// This is the sibling to LSet.
//
// Dim MyString as String = "0123456789"
// Rset(MyString) = "Right->"
//
// MyString contains " Right->".
// First, calculate the end length of the destination
Dim destLen As Integer = Len(dest)
Dim sourceLen As Integer = Len(source)
// If the source string is greater than the
// destination, we want to trim the source
// string and just be done
If sourceLen >= destLen Then
dest = Right(source, destLen)
Return
End If
// Otherwise, we're stuck doing it the "hard" way.
// First, calculate how many spaces we need to
// add to fill the rest of the length
Dim numSpaces As Integer = destLen - sourceLen
// Now add the spaces
dest = Space(numSpaces)
// Then, assign the source (this would make it right-aligned).
dest = dest + source
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub SavePicture(p As Picture, name As String)
// We want to save the given picture in a file, which
// Xojo pretty much already handles for you.
// Check to see if the path is an absolute path, or
// just a local one
Dim fileToSave As FolderItem
fileToSave = GetCurrentDirectory.Child(name)
// Then save the picture out
fileToSave.SaveAsPicture(p)
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub SaveSetting(appName As String, section As String, key As String, setting As Variant)
#If TargetWindows
// First, we want to get to the default location for all VB apps
Dim base As New RegistryItem(kSettingsLocation)
// Then we want to dive into the app and section folders
base = base.Child(appName).Child(section)
// Now we want to save the key and value
base.Value(key) = setting
Exception err As RegistryAccessErrorException
// Just bail out
Return
#Endif
End Sub
#tag EndMethod
#tag Method, Flags = &h1
Protected Function Second() As Integer
// Return the current second
Return Xojo.Core.Date.Now.Second
End Function
#tag EndMethod
#tag Method, Flags = &h1
Protected Sub SendKeys(keys As String, unused As Boolean = False)
#If TargetWindows
// We want to initialize all of our virtual keys. Some of them
// are going to be constants, others will be figured out while
// we parse, and still others will reside in a map.
Const VK_SHIFT = &h10
Const VK_CONTROL = &h11
Const VK_MENU = &h12
Const VK_ENTER = &h0D