SourceCodeManagerUtilities.st
changeset 1375 80969e1428a8
parent 1374 e351232c03e0
child 1377 0fd99dd003f6
equal deleted inserted replaced
1374:e351232c03e0 1375:80969e1428a8
    96     LastPackage := something.
    96     LastPackage := something.
    97 ! !
    97 ! !
    98 
    98 
    99 !SourceCodeManagerUtilities class methodsFor:'utilities'!
    99 !SourceCodeManagerUtilities class methodsFor:'utilities'!
   100 
   100 
   101 askForContainer:boxText title:title note:notice initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName
   101 setPackageOfAllMethodsIn:aClass to:aPackage
   102     "open a dialog asking for a source container;
   102     "make all methods belong to the classes project"
   103      return a dictionary containing module, package and filename,
   103 
   104      or nil if canceled."
   104     |anyChange anyChangeHere|
   105 
   105 
   106     ^ self
   106     anyChange := false.
   107         askForContainer:boxText title:title note:notice 
   107     aClass withAllPrivateClassesDo:[:eachClass |
   108         initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName 
   108         anyChangeHere := false.
   109         forNewContainer:true
   109         eachClass instAndClassSelectorsAndMethodsDo:[:sel :mthd | 
   110 !
   110             mthd package ~= aPackage ifTrue:[
   111 
   111                 mthd setPackage:aPackage.
   112 askForContainer:boxText title:title note:notice initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName forNewContainer:forNewContainer
   112                 anyChangeHere := true.
   113     "open a dialog asking for a source container;
   113             ].
   114      return a dictionary containing module, package and filename,
   114         ].
   115      or nil if canceled."
   115         anyChangeHere ifTrue:[
   116 
   116             eachClass changed:#projectOrganization
   117     |box y component resources answer
   117         ].
   118      moduleHolder packageHolder fileNameHolder
   118         anyChangeHere ifTrue:[anyChange := true].
   119      module package fileName 
   119     ].
   120      knownContainers knownPackages packageUpdater
   120     anyChange ifTrue:[
   121      packageBoxComponent fileNameBoxComponent fileNameUpdater|
   121        Smalltalk changed:#projectOrganization
   122 
   122     ].
   123     knownContainers := Set new.
   123     ^ anyChange
   124     Smalltalk allClassesDo:[:cls | |pckg|
   124 !
   125         pckg := cls package.
   125 
   126         pckg size > 0 ifTrue:[
   126 sourceCodeManagerFor:aClass
   127             knownContainers add:(pckg upTo:$:)
   127     |mgr|
   128         ]
   128 
   129     ].
   129     mgr := (aClass sourceCodeManager).
   130     knownContainers := knownContainers asOrderedCollection.
   130     mgr isNil ifTrue:[
   131     knownContainers := knownContainers select:[:module | module isBlank not].
   131         SourceCodeManager isNil ifTrue:[
   132     knownContainers sort.
   132             (self warn:'SourceCodeManagement is disabled or not configured.\\Please setup in the Launcher.' withCRs) ifFalse:[
   133 
       
   134     packageUpdater := [
       
   135         |theModulePrefix|
       
   136 
       
   137         theModulePrefix := moduleHolder value , ':'.
       
   138 
       
   139         Cursor wait showWhile:[
       
   140             knownPackages := Set new.
       
   141             Smalltalk allClassesDo:[:cls | |pckg idx|
       
   142                 pckg := cls package.
       
   143                 pckg size > 0 ifTrue:[
       
   144                     (pckg startsWith:theModulePrefix) ifTrue:[
       
   145                         idx := pckg indexOf:$:.
       
   146                         knownPackages add:(pckg copyFrom:idx + 1)
       
   147                     ]
       
   148                 ]
       
   149             ].
       
   150             knownPackages := knownPackages asOrderedCollection.
       
   151             knownPackages := knownPackages select:[:package | package isBlank not].
       
   152             knownPackages sort.
       
   153             packageBoxComponent list:knownPackages.
       
   154         ].
       
   155     ].
       
   156 
       
   157     fileNameUpdater := [
       
   158         |module package files|
       
   159 
       
   160         Cursor read showWhile:[
       
   161             module := moduleHolder value ? '__NoProject__'.
       
   162             package := packageHolder value ? '__NoProject__'.
       
   163 
       
   164             files := SourceCodeManager getExistingContainersInModule:module package:package.
       
   165             files := files asOrderedCollection.
       
   166             files := files select:[:eachFile | eachFile asFilename hasSuffix:'st'].
       
   167             files sort.
       
   168             fileNameBoxComponent list:files.
       
   169         ].
       
   170     ].
       
   171 
       
   172     moduleHolder := initialModule asValue.
       
   173     packageHolder := initialPackage asValue.
       
   174     fileNameHolder := initialFileName asValue.
       
   175 
       
   176     resources := ResourcePack for:self.
       
   177 
       
   178     "/
       
   179     "/ open a dialog for this
       
   180     "/
       
   181     box := DialogBox new.
       
   182     box label:title.
       
   183 
       
   184     component := box addTextLabel:boxText withCRs.
       
   185     component adjust:#left; borderWidth:0.
       
   186     box addVerticalSpace.
       
   187     box addVerticalSpace.
       
   188 
       
   189     y := box yPosition.
       
   190     component := box addTextLabel:(resources string:'Module:').
       
   191     component width:0.4; adjust:#right.
       
   192     box yPosition:y.
       
   193     component := box addComboBoxOn:moduleHolder tabable:true.
       
   194     component list:knownContainers.
       
   195 
       
   196 "/    component := box addInputFieldOn:moduleHolder tabable:true.
       
   197     component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine.
       
   198 
       
   199     box addVerticalSpace.
       
   200     y := box yPosition.
       
   201     component := box addTextLabel:(resources string:'Package:').
       
   202     component width:0.4; adjust:#right.
       
   203     box yPosition:y.
       
   204     packageBoxComponent := component := box addComboBoxOn:packageHolder tabable:true.
       
   205 "/    component := box addInputFieldOn:packageHolder tabable:true.
       
   206     component width:0.6; left:0.4; "immediateAccept:true; "acceptOnLeave:true; cursorMovementWhenUpdating:#beginOfLine.
       
   207     packageUpdater value.
       
   208     moduleHolder onChangeEvaluate:packageUpdater.
       
   209 
       
   210     box addVerticalSpace.
       
   211     y := box yPosition.
       
   212     component := box addTextLabel:(resources string:'Filename:').
       
   213     component width:0.4; adjust:#right.
       
   214     box yPosition:y.
       
   215 
       
   216     forNewContainer ifTrue:[
       
   217         component := box addInputFieldOn:fileNameHolder tabable:true.
       
   218         component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine.
       
   219     ] ifFalse:[
       
   220         fileNameBoxComponent := component := box addComboBoxOn:fileNameHolder tabable:true.
       
   221         component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine.
       
   222         fileNameUpdater value.
       
   223         packageHolder onChangeEvaluate:fileNameUpdater.
       
   224     ].
       
   225 
       
   226     box addVerticalSpace.
       
   227 
       
   228     notice notNil ifTrue:[
       
   229         component := box addTextLabel:notice.
       
   230         component adjust:#left; borderWidth:0.
       
   231     ].
       
   232 
       
   233     box addVerticalSpace.
       
   234     box addAbortAndOkButtons.
       
   235 
       
   236     (YesToAllNotification notNil and:[YesToAllNotification isHandled]) ifTrue:[
       
   237         component := Button label:'Yes to all'.
       
   238         component action:[
       
   239                             YesToAllNotification queryWith:true.
       
   240                             box doAccept.
       
   241                          ].
       
   242         (DialogBox defaultOKButtonAtLeft) ifTrue:[
       
   243             box addButton:component after:nil.
       
   244         ] ifFalse:[
       
   245             box addButton:component before:nil.
       
   246         ].
       
   247     ].
       
   248     (AbortAllSignal isHandled) ifTrue:[
       
   249         component := Button label:'Cancel all'.
       
   250         component action:[
       
   251                             box hide.
       
   252                             AbortAllSignal raiseSignal.
       
   253                          ].
       
   254         (DialogBox defaultOKButtonAtLeft) ifTrue:[
       
   255             box addButton:component before:nil.
       
   256         ] ifFalse:[
       
   257             box addButton:component after:nil.
       
   258         ].
       
   259     ].
       
   260 
       
   261     (YesToAllQuery notNil and:[YesToAllQuery isHandled]) ifTrue:[
       
   262         answer := YesToAllQuery query.
       
   263     ].
       
   264 
       
   265     answer isNil ifTrue:[
       
   266         box showAtPointer.
       
   267         answer := box accepted
       
   268     ].
       
   269 
       
   270     box destroy.
       
   271     answer ifFalse:[
       
   272         ^ nil
       
   273     ].
       
   274 
       
   275     module := moduleHolder value withoutSpaces.
       
   276     package := packageHolder value withoutSpaces.
       
   277     fileName := fileNameHolder value withoutSpaces.
       
   278     ^ Dictionary new
       
   279         at:#module put:module;
       
   280         at:#package put:package;
       
   281         at:#fileName put:fileName;
       
   282         yourself
       
   283 
       
   284     "
       
   285      self 
       
   286         askForContainer:'enter container' title:'container' note:'some note'
       
   287         initialModule:'foo' initialPackage:'bar' initialFileName:'baz'        
       
   288     "
       
   289 !
       
   290 
       
   291 askForExistingRevision:boxText title:title class:aClass
       
   292     "open a dialog asking for a containers revision;
       
   293      return a revision number, or nil if canceled."
       
   294 
       
   295     |mgr sourceInfo module package fileName|
       
   296 
       
   297     mgr := aClass sourceCodeManager.
       
   298     sourceInfo := mgr sourceInfoOfClass:aClass.
       
   299     sourceInfo isNil ifTrue:[^ nil].
       
   300 
       
   301     package := mgr packageFromSourceInfo:sourceInfo.
       
   302     module := mgr moduleFromSourceInfo:sourceInfo.  
       
   303     fileName := mgr containerFromSourceInfo:sourceInfo.
       
   304     ^ self
       
   305         askForExistingRevision:boxText 
       
   306         title:title 
       
   307         class:aClass 
       
   308         manager:mgr 
       
   309         module:module package:package fileName:fileName
       
   310 
       
   311     "
       
   312      SourceCodeManagerUtilities
       
   313         askForRevisionToCompare:'enter revision'
       
   314         title:'revision'
       
   315         class:Array
       
   316     "
       
   317 !
       
   318 
       
   319 askForExistingRevision:boxText title:title class:clsOrNil manager:aSourceCodeManager module:module package:package fileName:fileName
       
   320     "open a dialog asking for a containers revision;
       
   321      return a revision number, or nil if canceled."
       
   322 
       
   323     |partialLog revisions items newestRev
       
   324      box y component resources 
       
   325      revisionHolder|
       
   326 
       
   327     partialLog := aSourceCodeManager
       
   328         revisionLogOf:clsOrNil
       
   329         numberOfRevisions:20
       
   330         fileName:fileName
       
   331         directory:package 
       
   332         module:module.
       
   333     partialLog notNil ifTrue:[
       
   334         newestRev := partialLog at:#newestRevision.
       
   335         revisions := partialLog at:#revisions.
       
   336         items := revisions collect:[:each | |rev date who|
       
   337                                         rev := each at:#revision.
       
   338                                         date := each at:#date.
       
   339                                         who := each at:#author.
       
   340                                         rev allBold , ' [' , date , ' by ' , who , ']'
       
   341                                    ].
       
   342         revisions := revisions collect:[:each | each at:#revision].
       
   343     ] ifFalse:[
       
   344         newestRev := aSourceCodeManager newestRevisionInFile:fileName directory:package module:module.
       
   345         revisions := items := nil.
       
   346 
       
   347         newestRev isNil ifTrue:[
       
   348             (aSourceCodeManager checkForExistingContainerInModule:module package:package container:fileName)
       
   349             ifFalse:[
       
   350                 self warn:'Could not find/access the container for ',fileName,' in the repository.
       
   351 This could be due to:
       
   352     - invalid/wrong CVS-Root setting
       
   353     - missing CVS access rights
       
   354         (no access / not logged in)
       
   355     - changed CVSRoot after compilation
       
   356         (i.e. wrong CVS-path in classes version method)
       
   357 '.
       
   358                 ^ nil
   133                 ^ nil
   359             ]
   134             ].
   360         ]
   135         ].
   361     ].
   136         (self confirm:'Class does not seem to provide a valid sourceCodeManager.\\Assume CVS ?' withCRs) ifFalse:[
   362     revisionHolder  := newestRev asValue.
   137             ^ nil
   363     resources := ResourcePack for:self.
   138         ].
   364 
   139         mgr := CVSSourceCodeManager.
   365     revisionHolder onChangeEvaluate:[
   140     ].
   366         "/ cut off everything after revision
   141     ^ mgr
   367         |s first words|
   142 ! !
   368 
   143 
   369         s := revisionHolder value.
   144 !SourceCodeManagerUtilities class methodsFor:'utilities-cvs'!
   370         words := s asCollectionOfWords.
       
   371         words size > 0 ifTrue:[
       
   372             first := words first string.
       
   373             first ~= s ifTrue:[
       
   374                 revisionHolder value:first
       
   375             ]
       
   376         ]
       
   377     ].
       
   378 
       
   379     "/
       
   380     "/ open a dialog for this
       
   381     "/
       
   382     box := DialogBox new.
       
   383     box label:title.
       
   384 
       
   385     component := box addTextLabel:boxText withCRs.
       
   386     component adjust:#left; borderWidth:0.
       
   387     box addVerticalSpace.
       
   388     box addVerticalSpace.
       
   389 
       
   390     y := box yPosition.
       
   391     component := box addTextLabel:(resources string:'Revision:').
       
   392     component width:0.4; adjust:#right.
       
   393     box yPosition:y.
       
   394     component := box addComboBoxOn:revisionHolder tabable:true.
       
   395     component list:items.
       
   396     component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine.
       
   397 
       
   398     box addVerticalSpace.
       
   399 
       
   400     box addAbortAndOkButtons.
       
   401 
       
   402     Object abortAllSignal isHandled ifTrue:[
       
   403         (box addAbortButtonLabelled:'Cancel all') action:[AbortAllSignal raise].
       
   404     ].
       
   405 
       
   406     box showAtPointer.
       
   407 
       
   408     box accepted ifFalse:[
       
   409         box destroy.
       
   410         ^ nil
       
   411     ].
       
   412     box destroy.
       
   413 
       
   414     ^ revisionHolder value withoutSpaces.
       
   415 
       
   416     "
       
   417      SourceCodeManagerUtilities
       
   418         askForRevisionToCompare:'enter revision'
       
   419         title:'revision'
       
   420         class:nil
       
   421         manager:SourceCodeManager 
       
   422         module:'stx'
       
   423         package:'libbasic'
       
   424         fileName:'Array.st'
       
   425     "
       
   426 !
       
   427 
       
   428 checkAndWarnAboutBadMessagesInClass:aClass
       
   429     "check if a class contains message-sends to:
       
   430         #halt
       
   431         #halt:
       
   432         #error
       
   433         (and maybe more in the future)"
       
   434 
       
   435     |badStuff whatIsBad msg answer labels values|
       
   436 
       
   437     badStuff := #(
       
   438         ( #halt         'sent of #halt (use for debugging only) - better use #error:''some message''' )
       
   439         ( #halt:        'sent of #halt: (use for debugging only) - better use #error:' )
       
   440         ( #error        'sent of #error without descriptive message - better use #error:''some message''' )
       
   441     ).
       
   442 
       
   443     whatIsBad := Set new.
       
   444     aClass theNonMetaclass instAndClassSelectorsAndMethodsDo:[:sel :mthd |
       
   445         |setOfLiterals setOfSentMessages|
       
   446 
       
   447         setOfLiterals := mthd literals.  "/ try without parsing first.
       
   448         (badStuff contains:[:eachEntry | setOfLiterals includes:eachEntry first]) ifTrue:[
       
   449             setOfSentMessages := mthd messagesSent.
       
   450             badStuff do:[:eachEntry |
       
   451                 (setOfSentMessages includes:eachEntry first) ifTrue:[
       
   452                     whatIsBad add:eachEntry second
       
   453                 ]
       
   454             ].
       
   455         ].
       
   456     ].
       
   457     whatIsBad notEmpty ifTrue:[
       
   458         (YesToAllQuery notNil and:[YesToAllQuery isHandled]) ifTrue:[
       
   459             answer := YesToAllQuery query.
       
   460             answer notNil ifTrue:[ ^ answer ].
       
   461         ].
       
   462 
       
   463         msg := '%1 contains the following  (considered bad style) message sends:\\'.
       
   464         whatIsBad do:[:each |
       
   465             msg := msg , '   ' , each , '\'
       
   466         ].
       
   467         msg := msg , '\\' , 'Do you really want to checkIn the %1 class ?'.
       
   468         msg := msg bindWith:aClass name.
       
   469         (YesToAllNotification notNil and:[YesToAllNotification isHandled]) ifTrue:[
       
   470             labels := #('Yes' 'Yes to all' 'No' 'No to all' 'Cancel').
       
   471             values := #(true #yesToAll false #noToAll nil).
       
   472             AbortAllSignal isHandled ifTrue:[
       
   473                 labels := labels , #('Cancel All').
       
   474                 values := values , #(#cancelAll).
       
   475             ].
       
   476             answer := OptionBox 
       
   477                           request:msg withCRs
       
   478                           label:'Really checkIn ?'
       
   479                           form:(InfoBox iconBitmap)
       
   480                           buttonLabels:labels
       
   481                           values:values
       
   482                           default:#yesToAll
       
   483                           onCancel:nil.
       
   484             answer isNil ifTrue:[
       
   485                 AbortSignal raise.
       
   486             ].
       
   487             answer == #cancelAll ifTrue:[
       
   488                 AbortAllSignal raise.
       
   489             ].
       
   490 
       
   491             answer == #yesToAll ifTrue:[
       
   492                 YesToAllNotification queryWith:true.
       
   493                 ^ true
       
   494             ].
       
   495             answer == #noToAll ifTrue:[
       
   496                 YesToAllNotification queryWith:false.
       
   497                 ^ false
       
   498             ].
       
   499             ^ answer
       
   500         ] ifFalse:[
       
   501             ^ self confirm:msg withCRs
       
   502         ]
       
   503     ].
       
   504     ^ true.
       
   505 
       
   506     "
       
   507      self checkAndWarnAboutBadMessagesInClass:(SourceCodeManagerUtilities)  
       
   508     "
       
   509 !
       
   510 
   145 
   511 checkForExistingModule:module package:package container:containerFileName using:mgr allowCreate:allowCreate
   146 checkForExistingModule:module package:package container:containerFileName using:mgr allowCreate:allowCreate
   512     |resources moduleName packageName containerName|
   147     |resources moduleName packageName containerName|
   513 
   148 
   514     resources := ResourcePack for:self.
   149     resources := ResourcePack for:self.
  1728         ^ false.
  1363         ^ false.
  1729     ].
  1364     ].
  1730     ^ true
  1365     ^ true
  1731 !
  1366 !
  1732 
  1367 
  1733 getLogMessageFor:aString
       
  1734     "get a log message for checking in a class.
       
  1735      Return the message or nil if aborted."
       
  1736 
       
  1737     ^ self getLogMessageFor:aString initialAnswer:LastSourceLogMessage
       
  1738 
       
  1739     "
       
  1740      SourceCodeManagerUtilities getLogMessageFor:'hello'
       
  1741     "
       
  1742 !
       
  1743 
       
  1744 getLogMessageFor:aString initialAnswer:initialAnswer
       
  1745     "get a log message for checking in a class.
       
  1746      Return the message or nil if aborted."
       
  1747 
       
  1748     |resources logMsg|
       
  1749 
       
  1750     resources := ResourcePack for:self.
       
  1751     logMsg := Dialog
       
  1752         requestText:(resources string:'Enter log message for: %1' with:aString allBold)
       
  1753         lines:10
       
  1754         columns:70
       
  1755         initialAnswer:(initialAnswer ? LastSourceLogMessage ? '').
       
  1756 
       
  1757     logMsg notNil ifTrue:[
       
  1758         LastSourceLogMessage := logMsg
       
  1759     ].
       
  1760     ^ logMsg
       
  1761 
       
  1762     "
       
  1763      SourceCodeManagerUtilities getLogMessageFor:'hello'
       
  1764     "
       
  1765 !
       
  1766 
       
  1767 getLogMessageFor:aString withButton:additionalButton
       
  1768     "get a log message for checking in a class.
       
  1769      Return the message or nil if aborted."
       
  1770 
       
  1771     |resources logMsg dialog textHolder|
       
  1772 
       
  1773     resources := ResourcePack for:self.
       
  1774     textHolder := '' asValue.
       
  1775     dialog := Dialog 
       
  1776                 forRequestText:(resources string:'enter log message for: %1' with:aString)
       
  1777                 lines:10
       
  1778                 columns:70
       
  1779                 initialAnswer:LastSourceLogMessage
       
  1780                 model:textHolder.
       
  1781 
       
  1782     additionalButton notNil ifTrue:[
       
  1783         dialog addButton:additionalButton before:(dialog okButton).
       
  1784     ].
       
  1785 
       
  1786     dialog open.
       
  1787     dialog accepted ifFalse:[
       
  1788         ^ nil.
       
  1789     ].
       
  1790     logMsg := textHolder value.
       
  1791 "/    logMsg := Dialog
       
  1792 "/        requestText:(resources string:'enter log message for: %1' with:aString)
       
  1793 "/        lines:10
       
  1794 "/        columns:70
       
  1795 "/        initialAnswer:LastSourceLogMessage.
       
  1796     logMsg notNil ifTrue:[
       
  1797         LastSourceLogMessage := logMsg
       
  1798     ].
       
  1799     ^ logMsg
       
  1800 
       
  1801     "
       
  1802      SourceCodeManagerUtilities getLogMessageFor:'hello'
       
  1803      SourceCodeManagerUtilities getLogMessageFor:'hello' withButton:(Button label:'foo')
       
  1804     "
       
  1805 !
       
  1806 
       
  1807 getMethodVersionsOfClass:aClass selector:selector numberOfRevisions:numberOfRevisionsOrNil
       
  1808     "check-out all previous versions of aClass and retrieve the history of selector.
       
  1809      Return a dictionary associating revision with a changeList entries for that method.
       
  1810      Unfinished - need a GUI for that."
       
  1811 
       
  1812     |mgr theClass revisionLog revisions items s entriesPerRevision previousVersion|
       
  1813 
       
  1814     theClass := aClass theNonMetaclass.
       
  1815 
       
  1816     mgr := self sourceCodeManagerFor:theClass.
       
  1817     mgr isNil ifTrue:[
       
  1818         self error:'no sourceCodeManager'.
       
  1819     ].
       
  1820 
       
  1821     revisionLog := mgr
       
  1822                         revisionLogOf:theClass
       
  1823                         numberOfRevisions:numberOfRevisionsOrNil.
       
  1824 
       
  1825     revisions := revisionLog at:#revisions.
       
  1826     items := revisions collect:[:each | |rev date who|
       
  1827                                     rev := each at:#revision.
       
  1828                                     date := each at:#date.
       
  1829                                     who := each at:#author.
       
  1830                                     rev allBold , ' [' , date , ' by ' , who , ']'
       
  1831                                ].
       
  1832 
       
  1833     revisions := revisions collect:[:each | each at:#revision].
       
  1834     revisions addFirst:#current.
       
  1835     entriesPerRevision := Dictionary new.
       
  1836 
       
  1837     previousVersion := nil.
       
  1838     revisions reverseDo:[:eachRevision |
       
  1839         |srcStream entries thisVersion|
       
  1840 
       
  1841         eachRevision == #current ifTrue:[
       
  1842             s := '' writeStream.
       
  1843             theClass fileOutOn:s withTimeStamp:false.
       
  1844             srcStream := s contents readStream.
       
  1845         ] ifFalse:[
       
  1846             self activityNotification:('checking out revision ' , eachRevision , '...').
       
  1847             srcStream := mgr getSourceStreamFor:theClass revision:eachRevision.
       
  1848         ].
       
  1849 
       
  1850         entries := ChangeSet fromStream:srcStream.
       
  1851         srcStream close.
       
  1852 
       
  1853         "/ remove all definitions       
       
  1854         entries := entries select:[:each | each isMethodChange].
       
  1855         "/ remove all methods which are for other selectors      
       
  1856         entries := entries select:[:each | each selector == selector].
       
  1857         "/ remove all methods which are for private subclasses      
       
  1858         entries := entries select:[:each | each className = aClass name].
       
  1859 
       
  1860         entries size == 1 ifTrue:[
       
  1861             "/ the method is there
       
  1862             thisVersion := entries first.
       
  1863             (previousVersion notNil and:[previousVersion sameAs:thisVersion]) ifTrue:[
       
  1864                 "/ no change
       
  1865             ] ifFalse:[
       
  1866                 entriesPerRevision at:eachRevision put:thisVersion.
       
  1867             ].
       
  1868         ] ifFalse:[
       
  1869             "/ the method is not there
       
  1870         ].
       
  1871         previousVersion := thisVersion.
       
  1872     ].
       
  1873     self error:'unfinished code'.
       
  1874 
       
  1875     "
       
  1876      self getMethodVersionsOfClass:MenuPanel selector:#'helpTextForItem:' numberOfRevisions:20
       
  1877      self getMethodVersionsOfClass:NewLauncher class selector:#'menu' numberOfRevisions:20
       
  1878     "
       
  1879 !
       
  1880 
       
  1881 guessEncodingOfBuffer:buffer
       
  1882     "look for a string of the form
       
  1883             encoding #name
       
  1884      or:
       
  1885             encoding: name
       
  1886      within the given buffer 
       
  1887      (which is usually the first few bytes of a textFile)."
       
  1888 
       
  1889     |s idx w withoutQuotes lcBuffer enc|
       
  1890 
       
  1891     withoutQuotes := 
       
  1892         [ 
       
  1893             ((w startsWith:$") or:[(w startsWith:$')]) ifTrue:[
       
  1894                 w := w copyFrom:2
       
  1895             ].
       
  1896             ((w endsWith:$") or:[(w endsWith:$')]) ifTrue:[
       
  1897                 w := w copyWithoutLast:1
       
  1898             ].
       
  1899             w
       
  1900         ].
       
  1901 
       
  1902     lcBuffer := buffer asLowercase.
       
  1903 
       
  1904     #( 'charset' 'encoding' ) do:[:keyWord |
       
  1905         (idx := lcBuffer findString:keyWord) ~~ 0 ifTrue:[
       
  1906             s := ReadStream on:buffer.
       
  1907             s position1Based:idx.
       
  1908             s skip:keyWord size.
       
  1909             s skipSeparators. 
       
  1910 
       
  1911             ['=:#' includes:s peek] whileTrue:[
       
  1912                 s next.
       
  1913                 s skipSeparators. 
       
  1914             ].
       
  1915             s skipSeparators. 
       
  1916             w := s upToSeparator.
       
  1917             w notNil ifTrue:[
       
  1918                 enc := withoutQuotes value.
       
  1919                 (CharacterEncoder encoderFor:enc ifAbsent:nil) notNil ifTrue:[
       
  1920                     ^ enc asSymbol
       
  1921                 ].
       
  1922                 enc size >=3 ifTrue:[
       
  1923                     Transcript showCR:'Unknown encoding: ' , withoutQuotes value.
       
  1924                 ]
       
  1925             ].
       
  1926         ].
       
  1927     ].
       
  1928     ^ nil
       
  1929 !
       
  1930 
       
  1931 guessEncodingOfFile:aFilename
       
  1932     "look for a string
       
  1933         encoding #name
       
  1934      or:
       
  1935         encoding: name
       
  1936      within the given buffer 
       
  1937      (which is usually the first few bytes of a textFile).
       
  1938      If thats not found, use heuristics (in CharacterArray) to guess."
       
  1939 
       
  1940     |s buffer n "{Class: SmallInteger }"
       
  1941      binary enc|
       
  1942 
       
  1943     s := aFilename asFilename readStreamOrNil.
       
  1944     s isNil ifTrue:[^ nil].
       
  1945 
       
  1946     buffer := String new:2048.
       
  1947     n := buffer size.
       
  1948     n := s nextBytes:n into:buffer.
       
  1949     s close.
       
  1950 
       
  1951     enc := self guessEncodingOfBuffer:buffer.
       
  1952     enc notNil ifTrue:[^ enc].
       
  1953 
       
  1954     binary := false.
       
  1955     1 to:n do:[:i |
       
  1956         (buffer at:i) isPrintable ifFalse:[binary := true].
       
  1957     ].
       
  1958 
       
  1959     "/ look for JIS7 / EUC encoding
       
  1960     (buffer findString:(CharacterEncoder jisISO2022EscapeSequence)) ~~ 0 ifTrue:[
       
  1961         ^ #'iso2020-jp'
       
  1962     ].
       
  1963     (buffer findString:(CharacterEncoder jis7KanjiEscapeSequence)) ~~ 0 ifTrue:[
       
  1964         ^ #jis7
       
  1965     ].
       
  1966     (buffer findString:(CharacterEncoder jis7KanjiOldEscapeSequence)) ~~ 0 ifTrue:[
       
  1967         ^ #jis7
       
  1968     ].
       
  1969 
       
  1970     "/ TODO:
       
  1971 
       
  1972 "/    "/ look for EUC
       
  1973 "/    idx := aString findFirst:[:char | |ascii|
       
  1974 "/                                        ((ascii := char asciiValue) >= 16rA1)     
       
  1975 "/                                        and:[ascii <= 16rFE]].
       
  1976 "/    idx ~~ 0 ifTrue:[
       
  1977 "/        ascii := (aString at:(idx + 1)) asciiValue.
       
  1978 "/        (ascii >= 16rA1 and:[ascii <= 16rFE]) ifTrue:[
       
  1979 "/            ^ #euc
       
  1980 "/        ]
       
  1981 "/    ].
       
  1982     "/ look for SJIS ...
       
  1983 
       
  1984     ^ nil
       
  1985 
       
  1986     "
       
  1987      SourceCodeManagerUtilities guessEncodingOfFile:'../../libview2/resources/ApplicationModel_de.rs' asFilename
       
  1988      SourceCodeManagerUtilities guessEncodingOfFile:'../../libview2/resources/ApplicationModel_ru.rs' asFilename
       
  1989     "
       
  1990 !
       
  1991 
       
  1992 guessEncodingOfStream:aStream
       
  1993     "look for a string of the form
       
  1994             encoding #name
       
  1995      or:
       
  1996             encoding: name
       
  1997      in the first few bytes of aStream."
       
  1998 
       
  1999     |oldPosition buffer n|
       
  2000 
       
  2001     buffer := String new:2048.
       
  2002 
       
  2003     oldPosition := aStream position.
       
  2004     n := buffer size.
       
  2005     n := aStream nextBytes:n into:buffer.
       
  2006     aStream position:oldPosition.
       
  2007 
       
  2008     ^ self guessEncodingOfBuffer:buffer
       
  2009 !
       
  2010 
       
  2011 removeSourceContainerForClass:aClass
  1368 removeSourceContainerForClass:aClass
  2012     "show container & let user confirm twice."
  1369     "show container & let user confirm twice."
  2013 
  1370 
  2014     ^ self removeSourceContainerForClass:aClass confirm:true warn:true
  1371     ^ self removeSourceContainerForClass:aClass confirm:true warn:true
  2015 !
  1372 !
  2187             msg notNil ifTrue:[
  1544             msg notNil ifTrue:[
  2188                 aStream cr; nextPutAll:msg.
  1545                 aStream cr; nextPutAll:msg.
  2189             ]
  1546             ]
  2190         ]
  1547         ]
  2191     ]
  1548     ]
  2192 !
  1549 ! !
  2193 
  1550 
  2194 setPackageOfAllMethodsIn:aClass to:aPackage
  1551 !SourceCodeManagerUtilities class methodsFor:'utilities-cvs-helpers'!
  2195     "make all methods belong to the classes project"
  1552 
  2196 
  1553 getLogMessageFor:aString
  2197     |anyChange anyChangeHere|
  1554     "get a log message for checking in a class.
  2198 
  1555      Return the message or nil if aborted."
  2199     anyChange := false.
  1556 
  2200     aClass withAllPrivateClassesDo:[:eachClass |
  1557     ^ self getLogMessageFor:aString initialAnswer:LastSourceLogMessage
  2201         anyChangeHere := false.
  1558 
  2202         eachClass instAndClassSelectorsAndMethodsDo:[:sel :mthd | 
  1559     "
  2203             mthd package ~= aPackage ifTrue:[
  1560      SourceCodeManagerUtilities getLogMessageFor:'hello'
  2204                 mthd setPackage:aPackage.
  1561     "
  2205                 anyChangeHere := true.
  1562 !
  2206             ].
  1563 
  2207         ].
  1564 getLogMessageFor:aString initialAnswer:initialAnswer
  2208         anyChangeHere ifTrue:[
  1565     "get a log message for checking in a class.
  2209             eachClass changed:#projectOrganization
  1566      Return the message or nil if aborted."
  2210         ].
  1567 
  2211         anyChangeHere ifTrue:[anyChange := true].
  1568     |resources logMsg|
  2212     ].
  1569 
  2213     anyChange ifTrue:[
  1570     resources := ResourcePack for:self.
  2214        Smalltalk changed:#projectOrganization
  1571     logMsg := Dialog
  2215     ].
  1572         requestText:(resources string:'Enter log message for: %1' with:aString allBold)
  2216     ^ anyChange
  1573         lines:10
  2217 !
  1574         columns:70
  2218 
  1575         initialAnswer:(initialAnswer ? LastSourceLogMessage ? '').
  2219 sourceCodeManagerFor:aClass
  1576 
  2220     |mgr|
  1577     logMsg notNil ifTrue:[
  2221 
  1578         LastSourceLogMessage := logMsg
  2222     mgr := (aClass sourceCodeManager).
  1579     ].
       
  1580     ^ logMsg
       
  1581 
       
  1582     "
       
  1583      SourceCodeManagerUtilities getLogMessageFor:'hello'
       
  1584     "
       
  1585 !
       
  1586 
       
  1587 getLogMessageFor:aString withButton:additionalButton
       
  1588     "get a log message for checking in a class.
       
  1589      Return the message or nil if aborted."
       
  1590 
       
  1591     |resources logMsg dialog textHolder|
       
  1592 
       
  1593     resources := ResourcePack for:self.
       
  1594     textHolder := '' asValue.
       
  1595     dialog := Dialog 
       
  1596                 forRequestText:(resources string:'enter log message for: %1' with:aString)
       
  1597                 lines:10
       
  1598                 columns:70
       
  1599                 initialAnswer:LastSourceLogMessage
       
  1600                 model:textHolder.
       
  1601 
       
  1602     additionalButton notNil ifTrue:[
       
  1603         dialog addButton:additionalButton before:(dialog okButton).
       
  1604     ].
       
  1605 
       
  1606     dialog open.
       
  1607     dialog accepted ifFalse:[
       
  1608         ^ nil.
       
  1609     ].
       
  1610     logMsg := textHolder value.
       
  1611 "/    logMsg := Dialog
       
  1612 "/        requestText:(resources string:'enter log message for: %1' with:aString)
       
  1613 "/        lines:10
       
  1614 "/        columns:70
       
  1615 "/        initialAnswer:LastSourceLogMessage.
       
  1616     logMsg notNil ifTrue:[
       
  1617         LastSourceLogMessage := logMsg
       
  1618     ].
       
  1619     ^ logMsg
       
  1620 
       
  1621     "
       
  1622      SourceCodeManagerUtilities getLogMessageFor:'hello'
       
  1623      SourceCodeManagerUtilities getLogMessageFor:'hello' withButton:(Button label:'foo')
       
  1624     "
       
  1625 !
       
  1626 
       
  1627 getMethodVersionsOfClass:aClass selector:selector numberOfRevisions:numberOfRevisionsOrNil
       
  1628     "check-out all previous versions of aClass and retrieve the history of selector.
       
  1629      Return a dictionary associating revision with a changeList entries for that method.
       
  1630      Unfinished - need a GUI for that."
       
  1631 
       
  1632     |mgr theClass revisionLog revisions items s entriesPerRevision previousVersion|
       
  1633 
       
  1634     theClass := aClass theNonMetaclass.
       
  1635 
       
  1636     mgr := self sourceCodeManagerFor:theClass.
  2223     mgr isNil ifTrue:[
  1637     mgr isNil ifTrue:[
  2224         SourceCodeManager isNil ifTrue:[
  1638         self error:'no sourceCodeManager'.
  2225             (self warn:'SourceCodeManagement is disabled or not configured.\\Please setup in the Launcher.' withCRs) ifFalse:[
  1639     ].
       
  1640 
       
  1641     revisionLog := mgr
       
  1642                         revisionLogOf:theClass
       
  1643                         numberOfRevisions:numberOfRevisionsOrNil.
       
  1644 
       
  1645     revisions := revisionLog at:#revisions.
       
  1646     items := revisions collect:[:each | |rev date who|
       
  1647                                     rev := each at:#revision.
       
  1648                                     date := each at:#date.
       
  1649                                     who := each at:#author.
       
  1650                                     rev allBold , ' [' , date , ' by ' , who , ']'
       
  1651                                ].
       
  1652 
       
  1653     revisions := revisions collect:[:each | each at:#revision].
       
  1654     revisions addFirst:#current.
       
  1655     entriesPerRevision := Dictionary new.
       
  1656 
       
  1657     previousVersion := nil.
       
  1658     revisions reverseDo:[:eachRevision |
       
  1659         |srcStream entries thisVersion|
       
  1660 
       
  1661         eachRevision == #current ifTrue:[
       
  1662             s := '' writeStream.
       
  1663             theClass fileOutOn:s withTimeStamp:false.
       
  1664             srcStream := s contents readStream.
       
  1665         ] ifFalse:[
       
  1666             self activityNotification:('checking out revision ' , eachRevision , '...').
       
  1667             srcStream := mgr getSourceStreamFor:theClass revision:eachRevision.
       
  1668         ].
       
  1669 
       
  1670         entries := ChangeSet fromStream:srcStream.
       
  1671         srcStream close.
       
  1672 
       
  1673         "/ remove all definitions       
       
  1674         entries := entries select:[:each | each isMethodChange].
       
  1675         "/ remove all methods which are for other selectors      
       
  1676         entries := entries select:[:each | each selector == selector].
       
  1677         "/ remove all methods which are for private subclasses      
       
  1678         entries := entries select:[:each | each className = aClass name].
       
  1679 
       
  1680         entries size == 1 ifTrue:[
       
  1681             "/ the method is there
       
  1682             thisVersion := entries first.
       
  1683             (previousVersion notNil and:[previousVersion sameAs:thisVersion]) ifTrue:[
       
  1684                 "/ no change
       
  1685             ] ifFalse:[
       
  1686                 entriesPerRevision at:eachRevision put:thisVersion.
       
  1687             ].
       
  1688         ] ifFalse:[
       
  1689             "/ the method is not there
       
  1690         ].
       
  1691         previousVersion := thisVersion.
       
  1692     ].
       
  1693     self error:'unfinished code'.
       
  1694 
       
  1695     "
       
  1696      self getMethodVersionsOfClass:MenuPanel selector:#'helpTextForItem:' numberOfRevisions:20
       
  1697      self getMethodVersionsOfClass:NewLauncher class selector:#'menu' numberOfRevisions:20
       
  1698     "
       
  1699 ! !
       
  1700 
       
  1701 !SourceCodeManagerUtilities class methodsFor:'utilities-cvs-user interaction'!
       
  1702 
       
  1703 askForContainer:boxText title:title note:notice initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName
       
  1704     "open a dialog asking for a source container;
       
  1705      return a dictionary containing module, package and filename,
       
  1706      or nil if canceled."
       
  1707 
       
  1708     ^ self
       
  1709         askForContainer:boxText title:title note:notice 
       
  1710         initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName 
       
  1711         forNewContainer:true
       
  1712 !
       
  1713 
       
  1714 askForContainer:boxText title:title note:notice initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName forNewContainer:forNewContainer
       
  1715     "open a dialog asking for a source container;
       
  1716      return a dictionary containing module, package and filename,
       
  1717      or nil if canceled."
       
  1718 
       
  1719     |box y component resources answer
       
  1720      moduleHolder packageHolder fileNameHolder
       
  1721      module package fileName 
       
  1722      knownContainers knownPackages packageUpdater
       
  1723      packageBoxComponent fileNameBoxComponent fileNameUpdater|
       
  1724 
       
  1725     knownContainers := Set new.
       
  1726     Smalltalk allClassesDo:[:cls | |pckg|
       
  1727         pckg := cls package.
       
  1728         pckg size > 0 ifTrue:[
       
  1729             knownContainers add:(pckg upTo:$:)
       
  1730         ]
       
  1731     ].
       
  1732     knownContainers := knownContainers asOrderedCollection.
       
  1733     knownContainers := knownContainers select:[:module | module isBlank not].
       
  1734     knownContainers sort.
       
  1735 
       
  1736     packageUpdater := [
       
  1737         |theModulePrefix|
       
  1738 
       
  1739         theModulePrefix := moduleHolder value , ':'.
       
  1740 
       
  1741         Cursor wait showWhile:[
       
  1742             knownPackages := Set new.
       
  1743             Smalltalk allClassesDo:[:cls | |pckg idx|
       
  1744                 pckg := cls package.
       
  1745                 pckg size > 0 ifTrue:[
       
  1746                     (pckg startsWith:theModulePrefix) ifTrue:[
       
  1747                         idx := pckg indexOf:$:.
       
  1748                         knownPackages add:(pckg copyFrom:idx + 1)
       
  1749                     ]
       
  1750                 ]
       
  1751             ].
       
  1752             knownPackages := knownPackages asOrderedCollection.
       
  1753             knownPackages := knownPackages select:[:package | package isBlank not].
       
  1754             knownPackages sort.
       
  1755             packageBoxComponent list:knownPackages.
       
  1756         ].
       
  1757     ].
       
  1758 
       
  1759     fileNameUpdater := [
       
  1760         |module package files|
       
  1761 
       
  1762         Cursor read showWhile:[
       
  1763             module := moduleHolder value ? '__NoProject__'.
       
  1764             package := packageHolder value ? '__NoProject__'.
       
  1765 
       
  1766             files := SourceCodeManager getExistingContainersInModule:module package:package.
       
  1767             files := files asOrderedCollection.
       
  1768             files := files select:[:eachFile | eachFile asFilename hasSuffix:'st'].
       
  1769             files sort.
       
  1770             fileNameBoxComponent list:files.
       
  1771         ].
       
  1772     ].
       
  1773 
       
  1774     moduleHolder := initialModule asValue.
       
  1775     packageHolder := initialPackage asValue.
       
  1776     fileNameHolder := initialFileName asValue.
       
  1777 
       
  1778     resources := ResourcePack for:self.
       
  1779 
       
  1780     "/
       
  1781     "/ open a dialog for this
       
  1782     "/
       
  1783     box := DialogBox new.
       
  1784     box label:title.
       
  1785 
       
  1786     component := box addTextLabel:boxText withCRs.
       
  1787     component adjust:#left; borderWidth:0.
       
  1788     box addVerticalSpace.
       
  1789     box addVerticalSpace.
       
  1790 
       
  1791     y := box yPosition.
       
  1792     component := box addTextLabel:(resources string:'Module:').
       
  1793     component width:0.4; adjust:#right.
       
  1794     box yPosition:y.
       
  1795     component := box addComboBoxOn:moduleHolder tabable:true.
       
  1796     component list:knownContainers.
       
  1797 
       
  1798 "/    component := box addInputFieldOn:moduleHolder tabable:true.
       
  1799     component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine.
       
  1800 
       
  1801     box addVerticalSpace.
       
  1802     y := box yPosition.
       
  1803     component := box addTextLabel:(resources string:'Package:').
       
  1804     component width:0.4; adjust:#right.
       
  1805     box yPosition:y.
       
  1806     packageBoxComponent := component := box addComboBoxOn:packageHolder tabable:true.
       
  1807 "/    component := box addInputFieldOn:packageHolder tabable:true.
       
  1808     component width:0.6; left:0.4; "immediateAccept:true; "acceptOnLeave:true; cursorMovementWhenUpdating:#beginOfLine.
       
  1809     packageUpdater value.
       
  1810     moduleHolder onChangeEvaluate:packageUpdater.
       
  1811 
       
  1812     box addVerticalSpace.
       
  1813     y := box yPosition.
       
  1814     component := box addTextLabel:(resources string:'Filename:').
       
  1815     component width:0.4; adjust:#right.
       
  1816     box yPosition:y.
       
  1817 
       
  1818     forNewContainer ifTrue:[
       
  1819         component := box addInputFieldOn:fileNameHolder tabable:true.
       
  1820         component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine.
       
  1821     ] ifFalse:[
       
  1822         fileNameBoxComponent := component := box addComboBoxOn:fileNameHolder tabable:true.
       
  1823         component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine.
       
  1824         fileNameUpdater value.
       
  1825         packageHolder onChangeEvaluate:fileNameUpdater.
       
  1826     ].
       
  1827 
       
  1828     box addVerticalSpace.
       
  1829 
       
  1830     notice notNil ifTrue:[
       
  1831         component := box addTextLabel:notice.
       
  1832         component adjust:#left; borderWidth:0.
       
  1833     ].
       
  1834 
       
  1835     box addVerticalSpace.
       
  1836     box addAbortAndOkButtons.
       
  1837 
       
  1838     (YesToAllNotification notNil and:[YesToAllNotification isHandled]) ifTrue:[
       
  1839         component := Button label:'Yes to all'.
       
  1840         component action:[
       
  1841                             YesToAllNotification queryWith:true.
       
  1842                             box doAccept.
       
  1843                          ].
       
  1844         (DialogBox defaultOKButtonAtLeft) ifTrue:[
       
  1845             box addButton:component after:nil.
       
  1846         ] ifFalse:[
       
  1847             box addButton:component before:nil.
       
  1848         ].
       
  1849     ].
       
  1850     (AbortAllSignal isHandled) ifTrue:[
       
  1851         component := Button label:'Cancel all'.
       
  1852         component action:[
       
  1853                             box hide.
       
  1854                             AbortAllSignal raiseSignal.
       
  1855                          ].
       
  1856         (DialogBox defaultOKButtonAtLeft) ifTrue:[
       
  1857             box addButton:component before:nil.
       
  1858         ] ifFalse:[
       
  1859             box addButton:component after:nil.
       
  1860         ].
       
  1861     ].
       
  1862 
       
  1863     (YesToAllQuery notNil and:[YesToAllQuery isHandled]) ifTrue:[
       
  1864         answer := YesToAllQuery query.
       
  1865     ].
       
  1866 
       
  1867     answer isNil ifTrue:[
       
  1868         box showAtPointer.
       
  1869         answer := box accepted
       
  1870     ].
       
  1871 
       
  1872     box destroy.
       
  1873     answer ifFalse:[
       
  1874         ^ nil
       
  1875     ].
       
  1876 
       
  1877     module := moduleHolder value withoutSpaces.
       
  1878     package := packageHolder value withoutSpaces.
       
  1879     fileName := fileNameHolder value withoutSpaces.
       
  1880     ^ Dictionary new
       
  1881         at:#module put:module;
       
  1882         at:#package put:package;
       
  1883         at:#fileName put:fileName;
       
  1884         yourself
       
  1885 
       
  1886     "
       
  1887      self 
       
  1888         askForContainer:'enter container' title:'container' note:'some note'
       
  1889         initialModule:'foo' initialPackage:'bar' initialFileName:'baz'        
       
  1890     "
       
  1891 !
       
  1892 
       
  1893 askForExistingRevision:boxText title:title class:aClass
       
  1894     "open a dialog asking for a containers revision;
       
  1895      return a revision number, or nil if canceled."
       
  1896 
       
  1897     |mgr sourceInfo module package fileName|
       
  1898 
       
  1899     mgr := aClass sourceCodeManager.
       
  1900     sourceInfo := mgr sourceInfoOfClass:aClass.
       
  1901     sourceInfo isNil ifTrue:[^ nil].
       
  1902 
       
  1903     package := mgr packageFromSourceInfo:sourceInfo.
       
  1904     module := mgr moduleFromSourceInfo:sourceInfo.  
       
  1905     fileName := mgr containerFromSourceInfo:sourceInfo.
       
  1906     ^ self
       
  1907         askForExistingRevision:boxText 
       
  1908         title:title 
       
  1909         class:aClass 
       
  1910         manager:mgr 
       
  1911         module:module package:package fileName:fileName
       
  1912 
       
  1913     "
       
  1914      SourceCodeManagerUtilities
       
  1915         askForRevisionToCompare:'enter revision'
       
  1916         title:'revision'
       
  1917         class:Array
       
  1918     "
       
  1919 !
       
  1920 
       
  1921 askForExistingRevision:boxText title:title class:clsOrNil manager:aSourceCodeManager module:module package:package fileName:fileName
       
  1922     "open a dialog asking for a containers revision;
       
  1923      return a revision number, or nil if canceled."
       
  1924 
       
  1925     |partialLog revisions items newestRev
       
  1926      box y component resources 
       
  1927      revisionHolder|
       
  1928 
       
  1929     partialLog := aSourceCodeManager
       
  1930         revisionLogOf:clsOrNil
       
  1931         numberOfRevisions:20
       
  1932         fileName:fileName
       
  1933         directory:package 
       
  1934         module:module.
       
  1935     partialLog notNil ifTrue:[
       
  1936         newestRev := partialLog at:#newestRevision.
       
  1937         revisions := partialLog at:#revisions.
       
  1938         items := revisions collect:[:each | |rev date who|
       
  1939                                         rev := each at:#revision.
       
  1940                                         date := each at:#date.
       
  1941                                         who := each at:#author.
       
  1942                                         rev allBold , ' [' , date , ' by ' , who , ']'
       
  1943                                    ].
       
  1944         revisions := revisions collect:[:each | each at:#revision].
       
  1945     ] ifFalse:[
       
  1946         newestRev := aSourceCodeManager newestRevisionInFile:fileName directory:package module:module.
       
  1947         revisions := items := nil.
       
  1948 
       
  1949         newestRev isNil ifTrue:[
       
  1950             (aSourceCodeManager checkForExistingContainerInModule:module package:package container:fileName)
       
  1951             ifFalse:[
       
  1952                 self warn:'Could not find/access the container for ',fileName,' in the repository.
       
  1953 This could be due to:
       
  1954     - invalid/wrong CVS-Root setting
       
  1955     - missing CVS access rights
       
  1956         (no access / not logged in)
       
  1957     - changed CVSRoot after compilation
       
  1958         (i.e. wrong CVS-path in classes version method)
       
  1959 '.
  2226                 ^ nil
  1960                 ^ nil
  2227             ].
  1961             ]
  2228         ].
  1962         ]
  2229         (self confirm:'Class does not seem to provide a valid sourceCodeManager.\\Assume CVS ?' withCRs) ifFalse:[
  1963     ].
  2230             ^ nil
  1964     revisionHolder  := newestRev asValue.
  2231         ].
  1965     resources := ResourcePack for:self.
  2232         mgr := CVSSourceCodeManager.
  1966 
  2233     ].
  1967     revisionHolder onChangeEvaluate:[
  2234     ^ mgr
  1968         "/ cut off everything after revision
       
  1969         |s first words|
       
  1970 
       
  1971         s := revisionHolder value.
       
  1972         words := s asCollectionOfWords.
       
  1973         words size > 0 ifTrue:[
       
  1974             first := words first string.
       
  1975             first ~= s ifTrue:[
       
  1976                 revisionHolder value:first
       
  1977             ]
       
  1978         ]
       
  1979     ].
       
  1980 
       
  1981     "/
       
  1982     "/ open a dialog for this
       
  1983     "/
       
  1984     box := DialogBox new.
       
  1985     box label:title.
       
  1986 
       
  1987     component := box addTextLabel:boxText withCRs.
       
  1988     component adjust:#left; borderWidth:0.
       
  1989     box addVerticalSpace.
       
  1990     box addVerticalSpace.
       
  1991 
       
  1992     y := box yPosition.
       
  1993     component := box addTextLabel:(resources string:'Revision:').
       
  1994     component width:0.4; adjust:#right.
       
  1995     box yPosition:y.
       
  1996     component := box addComboBoxOn:revisionHolder tabable:true.
       
  1997     component list:items.
       
  1998     component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine.
       
  1999 
       
  2000     box addVerticalSpace.
       
  2001 
       
  2002     box addAbortAndOkButtons.
       
  2003 
       
  2004     Object abortAllSignal isHandled ifTrue:[
       
  2005         (box addAbortButtonLabelled:'Cancel all') action:[AbortAllSignal raise].
       
  2006     ].
       
  2007 
       
  2008     box showAtPointer.
       
  2009 
       
  2010     box accepted ifFalse:[
       
  2011         box destroy.
       
  2012         ^ nil
       
  2013     ].
       
  2014     box destroy.
       
  2015 
       
  2016     ^ revisionHolder value withoutSpaces.
       
  2017 
       
  2018     "
       
  2019      SourceCodeManagerUtilities
       
  2020         askForRevisionToCompare:'enter revision'
       
  2021         title:'revision'
       
  2022         class:nil
       
  2023         manager:SourceCodeManager 
       
  2024         module:'stx'
       
  2025         package:'libbasic'
       
  2026         fileName:'Array.st'
       
  2027     "
       
  2028 !
       
  2029 
       
  2030 checkAndWarnAboutBadMessagesInClass:aClass
       
  2031     "check if a class contains message-sends to:
       
  2032         #halt
       
  2033         #halt:
       
  2034         #error
       
  2035         (and maybe more in the future)"
       
  2036 
       
  2037     |badStuff whatIsBad msg answer labels values|
       
  2038 
       
  2039     badStuff := #(
       
  2040         ( #halt         'sent of #halt (use for debugging only) - better use #error:''some message''' )
       
  2041         ( #halt:        'sent of #halt: (use for debugging only) - better use #error:' )
       
  2042         ( #error        'sent of #error without descriptive message - better use #error:''some message''' )
       
  2043     ).
       
  2044 
       
  2045     whatIsBad := Set new.
       
  2046     aClass theNonMetaclass instAndClassSelectorsAndMethodsDo:[:sel :mthd |
       
  2047         |setOfLiterals setOfSentMessages|
       
  2048 
       
  2049         setOfLiterals := mthd literals.  "/ try without parsing first.
       
  2050         (badStuff contains:[:eachEntry | setOfLiterals includes:eachEntry first]) ifTrue:[
       
  2051             setOfSentMessages := mthd messagesSent.
       
  2052             badStuff do:[:eachEntry |
       
  2053                 (setOfSentMessages includes:eachEntry first) ifTrue:[
       
  2054                     whatIsBad add:eachEntry second
       
  2055                 ]
       
  2056             ].
       
  2057         ].
       
  2058     ].
       
  2059     whatIsBad notEmpty ifTrue:[
       
  2060         (YesToAllQuery notNil and:[YesToAllQuery isHandled]) ifTrue:[
       
  2061             answer := YesToAllQuery query.
       
  2062             answer notNil ifTrue:[ ^ answer ].
       
  2063         ].
       
  2064 
       
  2065         msg := '%1 contains the following  (considered bad style) message sends:\\'.
       
  2066         whatIsBad do:[:each |
       
  2067             msg := msg , '   ' , each , '\'
       
  2068         ].
       
  2069         msg := msg , '\\' , 'Do you really want to checkIn the %1 class ?'.
       
  2070         msg := msg bindWith:aClass name.
       
  2071         (YesToAllNotification notNil and:[YesToAllNotification isHandled]) ifTrue:[
       
  2072             labels := #('Yes' 'Yes to all' 'No' 'No to all' 'Cancel').
       
  2073             values := #(true #yesToAll false #noToAll nil).
       
  2074             AbortAllSignal isHandled ifTrue:[
       
  2075                 labels := labels , #('Cancel All').
       
  2076                 values := values , #(#cancelAll).
       
  2077             ].
       
  2078             answer := OptionBox 
       
  2079                           request:msg withCRs
       
  2080                           label:'Really checkIn ?'
       
  2081                           form:(InfoBox iconBitmap)
       
  2082                           buttonLabels:labels
       
  2083                           values:values
       
  2084                           default:#yesToAll
       
  2085                           onCancel:nil.
       
  2086             answer isNil ifTrue:[
       
  2087                 AbortSignal raise.
       
  2088             ].
       
  2089             answer == #cancelAll ifTrue:[
       
  2090                 AbortAllSignal raise.
       
  2091             ].
       
  2092 
       
  2093             answer == #yesToAll ifTrue:[
       
  2094                 YesToAllNotification queryWith:true.
       
  2095                 ^ true
       
  2096             ].
       
  2097             answer == #noToAll ifTrue:[
       
  2098                 YesToAllNotification queryWith:false.
       
  2099                 ^ false
       
  2100             ].
       
  2101             ^ answer
       
  2102         ] ifFalse:[
       
  2103             ^ self confirm:msg withCRs
       
  2104         ]
       
  2105     ].
       
  2106     ^ true.
       
  2107 
       
  2108     "
       
  2109      self checkAndWarnAboutBadMessagesInClass:(SourceCodeManagerUtilities)  
       
  2110     "
  2235 ! !
  2111 ! !
  2236 
  2112 
       
  2113 !SourceCodeManagerUtilities class methodsFor:'utilities-encoding'!
       
  2114 
       
  2115 guessEncodingOfBuffer:buffer
       
  2116     "look for a string of the form
       
  2117             encoding #name
       
  2118      or:
       
  2119             encoding: name
       
  2120      within the given buffer 
       
  2121      (which is usually the first few bytes of a textFile)."
       
  2122 
       
  2123     |s idx w withoutQuotes lcBuffer enc|
       
  2124 
       
  2125     withoutQuotes := 
       
  2126         [ 
       
  2127             ((w startsWith:$") or:[(w startsWith:$')]) ifTrue:[
       
  2128                 w := w copyFrom:2
       
  2129             ].
       
  2130             ((w endsWith:$") or:[(w endsWith:$')]) ifTrue:[
       
  2131                 w := w copyWithoutLast:1
       
  2132             ].
       
  2133             w
       
  2134         ].
       
  2135 
       
  2136     lcBuffer := buffer asLowercase.
       
  2137 
       
  2138     #( 'charset' 'encoding' ) do:[:keyWord |
       
  2139         (idx := lcBuffer findString:keyWord) ~~ 0 ifTrue:[
       
  2140             s := ReadStream on:buffer.
       
  2141             s position1Based:idx.
       
  2142             s skip:keyWord size.
       
  2143             s skipSeparators. 
       
  2144 
       
  2145             ['=:#' includes:s peek] whileTrue:[
       
  2146                 s next.
       
  2147                 s skipSeparators. 
       
  2148             ].
       
  2149             s skipSeparators. 
       
  2150             w := s upToSeparator.
       
  2151             w notNil ifTrue:[
       
  2152                 enc := withoutQuotes value.
       
  2153                 (CharacterEncoder encoderFor:enc ifAbsent:nil) notNil ifTrue:[
       
  2154                     ^ enc asSymbol
       
  2155                 ].
       
  2156                 enc size >=3 ifTrue:[
       
  2157                     Transcript showCR:'Unknown encoding: ' , withoutQuotes value.
       
  2158                 ]
       
  2159             ].
       
  2160         ].
       
  2161     ].
       
  2162     ^ nil
       
  2163 !
       
  2164 
       
  2165 guessEncodingOfFile:aFilename
       
  2166     "look for a string
       
  2167         encoding #name
       
  2168      or:
       
  2169         encoding: name
       
  2170      within the given buffer 
       
  2171      (which is usually the first few bytes of a textFile).
       
  2172      If thats not found, use heuristics (in CharacterArray) to guess."
       
  2173 
       
  2174     |s buffer n "{Class: SmallInteger }"
       
  2175      binary enc|
       
  2176 
       
  2177     s := aFilename asFilename readStreamOrNil.
       
  2178     s isNil ifTrue:[^ nil].
       
  2179 
       
  2180     buffer := String new:2048.
       
  2181     n := buffer size.
       
  2182     n := s nextBytes:n into:buffer.
       
  2183     s close.
       
  2184 
       
  2185     enc := self guessEncodingOfBuffer:buffer.
       
  2186     enc notNil ifTrue:[^ enc].
       
  2187 
       
  2188     binary := false.
       
  2189     1 to:n do:[:i |
       
  2190         (buffer at:i) isPrintable ifFalse:[binary := true].
       
  2191     ].
       
  2192 
       
  2193     "/ look for JIS7 / EUC encoding
       
  2194     (buffer findString:(CharacterEncoder jisISO2022EscapeSequence)) ~~ 0 ifTrue:[
       
  2195         ^ #'iso2020-jp'
       
  2196     ].
       
  2197     (buffer findString:(CharacterEncoder jis7KanjiEscapeSequence)) ~~ 0 ifTrue:[
       
  2198         ^ #jis7
       
  2199     ].
       
  2200     (buffer findString:(CharacterEncoder jis7KanjiOldEscapeSequence)) ~~ 0 ifTrue:[
       
  2201         ^ #jis7
       
  2202     ].
       
  2203 
       
  2204     "/ TODO:
       
  2205 
       
  2206 "/    "/ look for EUC
       
  2207 "/    idx := aString findFirst:[:char | |ascii|
       
  2208 "/                                        ((ascii := char asciiValue) >= 16rA1)     
       
  2209 "/                                        and:[ascii <= 16rFE]].
       
  2210 "/    idx ~~ 0 ifTrue:[
       
  2211 "/        ascii := (aString at:(idx + 1)) asciiValue.
       
  2212 "/        (ascii >= 16rA1 and:[ascii <= 16rFE]) ifTrue:[
       
  2213 "/            ^ #euc
       
  2214 "/        ]
       
  2215 "/    ].
       
  2216     "/ look for SJIS ...
       
  2217 
       
  2218     ^ nil
       
  2219 
       
  2220     "
       
  2221      SourceCodeManagerUtilities guessEncodingOfFile:'../../libview2/resources/ApplicationModel_de.rs' asFilename
       
  2222      SourceCodeManagerUtilities guessEncodingOfFile:'../../libview2/resources/ApplicationModel_ru.rs' asFilename
       
  2223     "
       
  2224 !
       
  2225 
       
  2226 guessEncodingOfStream:aStream
       
  2227     "look for a string of the form
       
  2228             encoding #name
       
  2229      or:
       
  2230             encoding: name
       
  2231      in the first few bytes of aStream."
       
  2232 
       
  2233     |oldPosition buffer n|
       
  2234 
       
  2235     buffer := String new:2048.
       
  2236 
       
  2237     oldPosition := aStream position.
       
  2238     n := buffer size.
       
  2239     n := aStream nextBytes:n into:buffer.
       
  2240     aStream position:oldPosition.
       
  2241 
       
  2242     ^ self guessEncodingOfBuffer:buffer
       
  2243 ! !
       
  2244 
  2237 !SourceCodeManagerUtilities class methodsFor:'documentation'!
  2245 !SourceCodeManagerUtilities class methodsFor:'documentation'!
  2238 
  2246 
  2239 version
  2247 version
  2240     ^ '$Header: /cvs/stx/stx/libbasic3/SourceCodeManagerUtilities.st,v 1.99 2004-03-11 15:39:08 cg Exp $'
  2248     ^ '$Header: /cvs/stx/stx/libbasic3/SourceCodeManagerUtilities.st,v 1.100 2004-03-12 09:36:02 cg Exp $'
  2241 ! !
  2249 ! !