1304 lines
36 KiB
Smalltalk
1304 lines
36 KiB
Smalltalk
"
|
|
I am a Grafoscopio Notebook.
|
|
|
|
Example:
|
|
| testTree nb |
|
|
testTree := GrafoscopioNode new becomeDefaultTestTree.
|
|
nb := GrafoscopioNotebook new.
|
|
nb notebookContent: testTree.
|
|
nb openWithSpec
|
|
"
|
|
Class {
|
|
#name : #GrafoscopioNewNotebook,
|
|
#superclass : #SpPresenter,
|
|
#instVars : [
|
|
'tree',
|
|
'header',
|
|
'body',
|
|
'links',
|
|
'windowMainMenu',
|
|
'workingFile',
|
|
'notebook',
|
|
'debugMessage',
|
|
'imagesList',
|
|
'exporting'
|
|
],
|
|
#classInstVars : [
|
|
'recents'
|
|
],
|
|
#category : #'Grafoscopio-UI'
|
|
}
|
|
|
|
{ #category : #utility }
|
|
GrafoscopioNewNotebook class >> SHA1For: aFile is: aSHA1String [
|
|
"I verify that a file has the same signature that the one in a given string,
|
|
returning true in that case or false otherwise"
|
|
^ (SHA1 new hashMessage: aFile asFileReference binaryReadStream contents) hex = aSHA1String
|
|
|
|
]
|
|
|
|
{ #category : #specs }
|
|
GrafoscopioNewNotebook class >> defaultSpec [
|
|
^ SpBoxLayout newVertical
|
|
add: #windowMainMenu
|
|
withConstraints: [ :constraints | constraints height: self toolbarHeight ];
|
|
add:
|
|
(SpPanedLayout newHorizontal
|
|
position: 250;
|
|
add: #tree;
|
|
add:
|
|
(SpBoxLayout newVertical
|
|
add: #header height: self toolbarHeight;
|
|
add: #body;
|
|
add: #links height: self toolbarHeight;
|
|
yourself);
|
|
yourself);
|
|
yourself
|
|
]
|
|
|
|
{ #category : #'instance creation' }
|
|
GrafoscopioNewNotebook class >> kindsOfNode [
|
|
^ GrafoscopioAbstractNode allSubclasses
|
|
]
|
|
|
|
{ #category : #'instance creation' }
|
|
GrafoscopioNewNotebook class >> newDefault [
|
|
^ self new.
|
|
]
|
|
|
|
{ #category : #'instance creation' }
|
|
GrafoscopioNewNotebook class >> open: aFileReference [
|
|
self newDefault openFromFile: aFileReference
|
|
]
|
|
|
|
{ #category : #'instance creation' }
|
|
GrafoscopioNewNotebook class >> recents [
|
|
^ recents ifNil: [ recents := Set new. ]
|
|
]
|
|
|
|
{ #category : #'instance creation' }
|
|
GrafoscopioNewNotebook class >> registerRecent: aFileReference [
|
|
recents add: aFileReference
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
GrafoscopioNewNotebook >> addCommandFrom: dictionary into: stream [
|
|
dictionary keysAndValuesDo: [ :k :v |
|
|
k = 'thisNotebook'
|
|
ifTrue: [
|
|
stream nextPutAll: (GrafoscopioUtils perform: v on: self) ]]
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> addNode [
|
|
| newNode kind |
|
|
kind := self chooseKindOfNode.
|
|
kind isClass
|
|
ifTrue: [ newNode := kind new.
|
|
self currentNode addNodeAfterMe: newNode.
|
|
self notebookContent: notebook.
|
|
self selectedItem: newNode ]
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> askToSaveBeforeClosing [
|
|
|
|
| saveChanges |
|
|
|
|
saveChanges := UIManager default
|
|
question: 'Do you want to save changes in the notebook before closing?'
|
|
title: 'Save changes before closing?'.
|
|
saveChanges ifNil: [ ^ self notebook unsavedNodes inspect ].
|
|
^ saveChanges
|
|
]
|
|
|
|
{ #category : #operation }
|
|
GrafoscopioNewNotebook >> autoSaveBodyOf: aNode [
|
|
| playground bodyContents |
|
|
bodyContents := aNode content.
|
|
self body class = GrafoscopioTextModel
|
|
ifTrue: [ self body body
|
|
whenTextChangedDo: [ :arg |
|
|
aNode content: arg.
|
|
"self body body whenTextIsAccepted: [:bodyText |
|
|
self inform: bodyText.
|
|
aNode updateEditionTimestamp ]."
|
|
bodyContents = arg
|
|
ifFalse: [ "self inform: arg.""aNode updateEditionTimestamp" ] ] ].
|
|
self body body class = GlamourPresentationModel
|
|
ifFalse: [ ^ self ].
|
|
playground := self body body glmPres.
|
|
playground
|
|
onChangeOfPort: #text
|
|
act: [ :x |
|
|
aNode content: (x pane port: #entity) value content
|
|
"aNode updateEditionTimestamp."
|
|
"self inform: aNode edited" ]
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> body [
|
|
^ body
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> body: anObject [
|
|
body := anObject
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
GrafoscopioNewNotebook >> checksumForRootSubtree [
|
|
"I return the checksum (crypto hash) of the workingFile where this notebook is being stored.
|
|
I'm useful for data provenance and traceability of derivated files coming from this source
|
|
notebook."
|
|
self workingFile ifNil: [ ^ self ].
|
|
self workingFile contents = '' ifTrue: [ ^ self ].
|
|
^ GrafoscopioUtils checksumFor: self workingFile
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> chooseKindOfNode [
|
|
| idx values |
|
|
values := self kindsOfNode.
|
|
idx := UIManager default
|
|
chooseFrom: values
|
|
lines: {}
|
|
title: 'What kind of node? '.
|
|
^ idx = 0
|
|
ifTrue: [ nil ]
|
|
ifFalse: [ values at: idx ]
|
|
]
|
|
|
|
{ #category : #'as yet unclassified' }
|
|
GrafoscopioNewNotebook >> content [
|
|
self shouldBeImplemented.
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> copyNodeToClipboard [
|
|
tree selectedItem copyToClipboard.
|
|
self notebookContent: notebook
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> createNewExample [
|
|
| node0 node1 |
|
|
node0 := GrafoscopioTextNode new
|
|
created: DateAndTime now ;
|
|
header: 'Arbol principal';
|
|
yourself.
|
|
node1 := GrafoscopioTextNode new
|
|
created: DateAndTime now;
|
|
header: 'Node 1';
|
|
body: '';
|
|
yourself.
|
|
node0 addNode: node1.
|
|
^ node0
|
|
]
|
|
|
|
{ #category : #operation }
|
|
GrafoscopioNewNotebook >> currentNode [
|
|
^ tree selectedItem
|
|
ifNil: [ notebook children
|
|
ifEmpty: [ notebook root ]
|
|
ifNotEmpty: [ notebook children first ] ]
|
|
]
|
|
|
|
{ #category : #operation }
|
|
GrafoscopioNewNotebook >> currentNodeContent [
|
|
^ self currentNode content
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> cutNodeToClipboard [
|
|
self copyNodeToClipboard; removeNode.
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> debugMessage [
|
|
^ debugMessage ifNil: [ self defineDebugMessageUI ]
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> debugMessage: aGrafoscopioNodeSelector [
|
|
"I define a message that can be used for debugging purposes in the current notebook."
|
|
debugMessage := aGrafoscopioNodeSelector
|
|
]
|
|
|
|
{ #category : #operation }
|
|
GrafoscopioNewNotebook >> debugWithSelector: aSymbol [
|
|
"I invoke a message to debug in the current node. In the future the debugging scope can be changed to
|
|
include different elements instead of the current node."
|
|
| currentNode nodeContent |
|
|
currentNode := tree highlightedItem.
|
|
currentNode ifNil: [ ^ self ].
|
|
nodeContent := currentNode content.
|
|
^ (nodeContent perform: aSymbol asSymbol) inspect
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
GrafoscopioNewNotebook >> defineDebugMessageUI [
|
|
| answer |
|
|
answer := UIManager default
|
|
request: 'Define debug message to be send to a selected node in this notebook.'
|
|
initialAnswer: 'messageNoDebugSelector'.
|
|
self debugMessage: answer
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> demoteNode [
|
|
| editedNode |
|
|
editedNode := tree selectedItem.
|
|
editedNode demote.
|
|
self notebookContent: notebook.
|
|
]
|
|
|
|
{ #category : #'as yet unclassified' }
|
|
GrafoscopioNewNotebook >> downloadImages [
|
|
"I download all images in a notebook into a local folder that respects relative paths.
|
|
So if a image refers to http://mysite.com/uploads/chap1/myimage.png, it will be stored
|
|
into: 'uploads/chap1/myimage.png' in the same folder where the notebook is stored.
|
|
This is helpful for notebooks conversions that expect to have local images in particular
|
|
locations."
|
|
|
|
| parentFolder |
|
|
parentFolder := UIManager default
|
|
chooseDirectory: 'Please, choose a destination for the images'
|
|
from:
|
|
(self workingFile
|
|
ifNil: [ FileLocator home ]
|
|
ifNotNil: [ self workingFile parent ]).
|
|
parentFolder
|
|
ifNotNil: [ ^ self imagesList
|
|
do: [ :each |
|
|
| relativePathString link |
|
|
link := each contents asUrl.
|
|
relativePathString := link directory.
|
|
relativePathString
|
|
ifNotEmpty: [ GrafoscopioUtils
|
|
ensureCreateDirectory: relativePathString
|
|
into: parentFolder ] ] ]
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> ensureNotExporting [
|
|
self isAlreadyExporting
|
|
ifTrue: [ ^ self error: ' Already exporting! Please wait ' ]
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> exportAllSubtreesAsMarkup [
|
|
| toBeExported |
|
|
toBeExported := self notebook selectMarkupSubtreesToExport.
|
|
toBeExported ifEmpty: [ ^ self ].
|
|
toBeExported do: [ :each | self subtreeAsMarkdownFileFor: each ].
|
|
self inform: toBeExported size asString , ' exported markdown subtrees.'
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> exportAsHTML [
|
|
"I export the current tree/document to a HTML file, using pandoc external app.
|
|
I suppose pandoc is already installed and available in the system."
|
|
|
|
| htmlFile |
|
|
self markdownFile exists
|
|
ifTrue: [ self markdownFile delete ].
|
|
self exportAsMarkdown.
|
|
htmlFile := self htmlFile.
|
|
htmlFile exists
|
|
ifTrue: [ htmlFile delete ].
|
|
self
|
|
exportUsing:
|
|
{'--standalone'.
|
|
self markdownFile fullName.
|
|
'--output'.
|
|
htmlFile fullName}
|
|
output: htmlFile fullName
|
|
"
|
|
|
|
|
|
Smalltalk platformName = 'Win32'
|
|
ifTrue: [WinProcess createProcess: 'pandoc --standalone ', self markdownFile fullName, ' -o ', htmlFile]."
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> exportAsLaTeX [
|
|
"I export the current tree/document to a LaTeX file, using pandoc external app.
|
|
I suppose pandoc is already installed and available in the system."
|
|
| texFile |
|
|
self markdownFile exists ifTrue: [ self markdownFile delete ].
|
|
self halt.
|
|
|
|
"self exportAsMarkdown.""<- This violates the separation of concenrs. Markdown exportation should
|
|
be explicit. There is still the issue of how to deal with desynchronization between a notebook
|
|
which has unsaved changes as markdown.... TO BE REVIWED!"
|
|
texFile := self markdownFile parent fullName,'/', self markdownFile basenameWithoutExtension, '.tex'.
|
|
texFile asFileReference exists ifTrue: [ texFile asFileReference delete ].
|
|
"OSProcess command: 'pandoc --standalone ', self markdownFile fullName, ' -o ', texFile."
|
|
self inform: ('File exported as: ', String cr, texFile).
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> exportAsMarkdown [
|
|
"I export the current working tree/document to a markdown file."
|
|
workingFile
|
|
ifNil: [ self inform: 'File NOT exported. Please save the notebook on hard drive first' ]
|
|
ifNotNil: [ self exportNode: (self notebook) asMarkdownIn: (self markdownFile) ]
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> exportAsPDF [
|
|
"I export the current tree/document to a PDF file, using pandoc and LaTeX external apps.
|
|
The latex engine used is xelatex, to minimize errors and warnings related with UTF8 support.
|
|
I suppose all them are already installed and defined in the system."
|
|
|
|
| pandocCommonCommand |
|
|
self ensureNotExporting.
|
|
self exportAsMarkdown.
|
|
self pdfFile ensureDelete.
|
|
pandocCommonCommand := self pandocOptionsComputed , ' '
|
|
, self markdownFile fullName , ' --output ' , self pdfFile fullName.
|
|
^ self
|
|
exportUsing: ((' ' split: pandocCommonCommand) reject: #isEmpty)
|
|
output: self pdfFile fullName
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> exportAsSton: aNotebook on: aFileStream [
|
|
aNotebook flatten.
|
|
self notebook root updateEditionTimestamp.
|
|
(STON writer on: aFileStream)
|
|
newLine: String crlf;
|
|
prettyPrint: true;
|
|
keepNewLines: true;
|
|
nextPut: aNotebook children.
|
|
|
|
]
|
|
|
|
{ #category : #utility }
|
|
GrafoscopioNewNotebook >> exportLinkContent [
|
|
Transcript show: (self currentNodeContent asMarkdown)
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> exportNode: aGrafoscopioNode asMarkdownIn: aFile [
|
|
"I export the current tree/document to a markdown file"
|
|
aFile ensureDelete.
|
|
aFile
|
|
ensureCreateFile;
|
|
writeStreamDo: [:stream |
|
|
stream
|
|
nextPutAll:
|
|
('---', String cr,
|
|
'exportedFrom: ', self checksumForRootSubtree, String cr) withInternetLineEndings.
|
|
aGrafoscopioNode metadataAsYamlIn: stream.
|
|
stream
|
|
nextPutAll:
|
|
('---', String cr, String cr) withInternetLineEndings,
|
|
aGrafoscopioNode asMarkdown ].
|
|
self inform: 'Exported as: ', String cr, aFile fullName
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> exportUsing: arguments [
|
|
self ensureNotExporting.
|
|
exporting := (#pandoc command arguments: arguments) future.
|
|
exporting
|
|
onSuccessDo: [ :val |
|
|
exporting := nil.
|
|
self
|
|
inform: 'File exported as: ' , String cr , self pdfFile fullName ].
|
|
exporting
|
|
onFailureDo: [ :e |
|
|
exporting := nil.
|
|
self
|
|
inform: 'Error exporting, ' , self pdfFile fullName , ': ' , e messageText ]
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> exportUsing: arguments output: aName [
|
|
self ensureNotExporting.
|
|
exporting := (#pandoc command arguments: arguments) future.
|
|
exporting
|
|
onSuccessDo: [ :val |
|
|
exporting := nil.
|
|
self inform: 'File exported as: ' , String cr , aName ].
|
|
exporting
|
|
onFailureDo: [ :e |
|
|
exporting := nil.
|
|
self inform: 'Error exporting, ' , aName , ': ' , e messageText ].
|
|
^ exporting
|
|
]
|
|
|
|
{ #category : #api }
|
|
GrafoscopioNewNotebook >> extent [
|
|
^900@500
|
|
]
|
|
|
|
{ #category : #'as yet unclassified' }
|
|
GrafoscopioNewNotebook >> findAndReplace [
|
|
| currentNode replaceGUI findString replaceString |
|
|
currentNode := tree selectedItem.
|
|
replaceGUI := GrafoscopioReplace new.
|
|
replaceGUI openWithSpec.
|
|
replaceGUI ok
|
|
on: [ ]
|
|
do: [
|
|
findString := replaceGUI returnValues at: 'find'.
|
|
replaceString := replaceGUI returnValues at: 'replace'.
|
|
currentNode find: findString andReplaceWith: replaceString. ]
|
|
|
|
]
|
|
|
|
{ #category : #testing }
|
|
GrafoscopioNewNotebook >> hasAWorkingFileDefined [
|
|
self workingFile ifNil: [ ^ false ] ifNotNil: [ ^ true ]
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> header [
|
|
^ header
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> header: anObject [
|
|
header := anObject
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> htmlFile [
|
|
^ (self markdownFile parent fullName , '/'
|
|
, self markdownFile basenameWithoutExtension , '.html')
|
|
asFileReference
|
|
]
|
|
|
|
{ #category : #operation }
|
|
GrafoscopioNewNotebook >> htmlToMarkdown [
|
|
self currentNodeContent htmlToMarkdown.
|
|
self updateBodyFor: self currentNode
|
|
]
|
|
|
|
{ #category : #operation }
|
|
GrafoscopioNewNotebook >> htmlToMarkdownSubtree [
|
|
self currentNodeContent htmlToMarkdownSubtree.
|
|
self updateBodyFor: self currentNode
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> imagesList [
|
|
imagesList ifNil: [ ^ #('No images list for this notebook') ].
|
|
^ imagesList
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> imagesList: anObject [
|
|
self halt.
|
|
imagesList := anObject
|
|
]
|
|
|
|
{ #category : #'as yet unclassified' }
|
|
GrafoscopioNewNotebook >> importImages [
|
|
self imagesList: (Pandoc listImagesFrom: self markdownFile).
|
|
self inform: 'All notebook images has been imported.', String cr, 'Now you can list and download them.'
|
|
]
|
|
|
|
{ #category : #operation }
|
|
GrafoscopioNewNotebook >> importLinkContent [
|
|
"I see if a node link is an url located at 'http://ws.stfx.eu', wich means that is a shared
|
|
workspace, and convert the node body to an interactive playground"
|
|
|
|
| currentNode |
|
|
currentNode := tree selectedItem.
|
|
currentNode ifNil: [ ^ self ].
|
|
currentNode importPlaygroundLink.
|
|
currentNode importHtmlLink.
|
|
self updateBodyFor: currentNode
|
|
]
|
|
|
|
{ #category : #initialization }
|
|
GrafoscopioNewNotebook >> initialize [
|
|
super initialize.
|
|
self notebook: self createNewExample.
|
|
self notebookContent: self notebook
|
|
]
|
|
|
|
{ #category : #initialization }
|
|
GrafoscopioNewNotebook >> initializePresenter [
|
|
tree
|
|
whenActivatedDo:
|
|
[ :selection | selection ifNotNil: [ self updateBodyFor: selection selectedItem ] ].
|
|
header
|
|
whenTextChangedDo: [ :arg |
|
|
tree selectedItem header = arg
|
|
ifFalse: [ tree selectedItem header: arg.
|
|
tree selectedItem updateEditionTimestamp.
|
|
tree roots: tree roots ] ].
|
|
links
|
|
whenTextChangedDo: [ :arg |
|
|
(tree respondsTo: #link:)
|
|
ifTrue: [ tree selectedItem link: arg.
|
|
tree selectedItem updateEditionTimestamp ] ]
|
|
]
|
|
|
|
{ #category : #initialization }
|
|
GrafoscopioNewNotebook >> initializeWidgets [
|
|
windowMainMenu := self topBar.
|
|
header := self newTextInput.
|
|
header autoAccept: true.
|
|
body := self newText.
|
|
body class traceCr.
|
|
body disable.
|
|
body text: '<- Select a node'.
|
|
body autoAccept: true.
|
|
links := self newTextInput.
|
|
tree := self newTreeTable.
|
|
tree addColumn: (SpStringTableColumn evaluated: #title).
|
|
" tree
|
|
childrenBlock: [ :node | node children value ];
|
|
displayBlock: [ :node | node title value ]."
|
|
self focusOrder
|
|
add: tree;
|
|
add: header;
|
|
add: body;
|
|
add: links.
|
|
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> initializeWindow: aWindowPresenter [
|
|
super initializeWindow: aWindowPresenter.
|
|
aWindowPresenter
|
|
title: ' New | Grafoscopio notebook';
|
|
windowIcon: self taskbarIcon;
|
|
askOkToClose: true
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> isAlreadyExporting [
|
|
^ exporting isNotNil
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> isSaved [
|
|
"I tell if a notebook has been saved in a persistence storage, including last editions."
|
|
^ self hasAWorkingFileDefined and: [self isSavedAfterLastEdition ].
|
|
]
|
|
|
|
{ #category : #testing }
|
|
GrafoscopioNewNotebook >> isSavedAfterLastEdition [
|
|
^ self notebook isSavedAfterLastEdition
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> kindsOfNode [
|
|
^ self class kindsOfNode
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> links [
|
|
^ links
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> links: anObject [
|
|
links := anObject
|
|
]
|
|
|
|
{ #category : #'as yet unclassified' }
|
|
GrafoscopioNewNotebook >> linksList [
|
|
| currentNode |
|
|
currentNode := tree selectedItem.
|
|
GrafoscopioLinksList new
|
|
content: currentNode;
|
|
openWithSpec
|
|
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
GrafoscopioNewNotebook >> listImagesUI [
|
|
ListPresenter new
|
|
title: 'Images files list';
|
|
items: self imagesList ;
|
|
openWithSpec
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> loadFromFile: aFileReference [
|
|
"I load the contents of aFileReference into a GrafoscopioNotebook, without opening it."
|
|
(aFileReference basename endsWith: 'ston') ifFalse: [ ^ self ].
|
|
self workingFile: aFileReference.
|
|
self notebook: ((STON fromString: self workingFile contents) at: 1) parent.
|
|
self title: self workingFile basenameWithIndicator, ' | Grafoscopio notebook'.
|
|
self notebookContent: self notebook.
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> markdownFile [
|
|
"I define the location of the markdown file where the notebook will be exported"
|
|
| markdownFile |
|
|
markdownFile := (((workingFile parent) / workingFile basenameWithoutExtension) fullName, '.markdown') asFileReference.
|
|
^ markdownFile
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
GrafoscopioNewNotebook >> markdownFileChecksum [
|
|
self workingFile ifNil: [ ^ self ].
|
|
self workingFile contents = '' ifTrue: [ ^ self ].
|
|
^ GrafoscopioUtils checksumFor: self markdownFile
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
GrafoscopioNewNotebook >> markdownFileChecksumUpto: anInteger [
|
|
"I cut the markdownFileCheckup upto a given integer.
|
|
Type coersion is needed, because this message argument can be read from a string in %metadata nodes.
|
|
Maybe the way used by playgrounds to import text as commands can be useful here."
|
|
^ self markdownFileChecksum copyFrom: 1 to: anInteger asInteger.
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
GrafoscopioNewNotebook >> metadata [
|
|
^ self notebook metadata
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> moveSelectedNodeDown [
|
|
| editedNode |
|
|
editedNode := tree selectedItem.
|
|
editedNode moveDown.
|
|
self notebookContent: notebook.
|
|
tree needRebuild: true
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> moveSelectedNodeUp [
|
|
| editedNode |
|
|
editedNode := tree selectedItem.
|
|
editedNode moveUp.
|
|
self notebookContent: notebook
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
GrafoscopioNewNotebook >> navigateRelativePathFor: aFileString [
|
|
"Given a relative path according to location of the notebook's workingFile,
|
|
I navigate to that file if exist and create it, including subdirectories if it does not exist.
|
|
If the relative path is located in a subdirectory that shares the route with the notebooks working
|
|
file, it must start with the folders name,
|
|
without using './' to point the same shared root "
|
|
|
|
| finalLocation pathSegments |
|
|
aFileString ifEmpty: [ ^ self ].
|
|
aFileString asUrl host ifNotNil: [ ^self ].
|
|
finalLocation := workingFile parent.
|
|
pathSegments := aFileString splitOn: '/'.
|
|
pathSegments allButLastDo: [ :segment |
|
|
(segment = '..')
|
|
ifTrue: [ finalLocation := finalLocation parent ]
|
|
ifFalse: [
|
|
finalLocation := finalLocation / segment.
|
|
finalLocation exists ifFalse: [ finalLocation ensureCreateDirectory ]]].
|
|
finalLocation := finalLocation / (pathSegments last).
|
|
finalLocation exists ifFalse: [ finalLocation ensureCreateFile ].
|
|
^ finalLocation
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> notebook [
|
|
^ notebook
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> notebook: anObject [
|
|
notebook := anObject
|
|
]
|
|
|
|
{ #category : #api }
|
|
GrafoscopioNewNotebook >> notebookContent: aTree [
|
|
tree roots: aTree children
|
|
]
|
|
|
|
{ #category : #initialization }
|
|
GrafoscopioNewNotebook >> notebookSubMenu [
|
|
^ SpMenuBarPresenter new
|
|
addGroup: [ :group |
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Save';
|
|
icon: (Smalltalk ui icons iconNamed: #smallSave);
|
|
shortcut: $s command;
|
|
action: [ self saveWorkingNotebook ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Save as...';
|
|
icon: (Smalltalk ui icons iconNamed: #smallSaveAs);
|
|
action: [ self saveToFileUI ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Import images';
|
|
icon: (Smalltalk ui icons iconNamed: #processBrowser);
|
|
action: [ self importImages ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'See images list';
|
|
icon: (Smalltalk ui icons iconNamed: #processBrowser);
|
|
action: [ self listImagesUI ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Download images';
|
|
icon: (Smalltalk ui icons iconNamed: #processBrowser);
|
|
action: [ self downloadImages ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Export as markdown';
|
|
icon: (Smalltalk ui icons iconNamed: #smallSaveAs);
|
|
action: [ self exportAsMarkdown ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Export as html';
|
|
icon: (Smalltalk ui icons iconNamed: #smallWindow);
|
|
action: [ self exportAsHTML ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Export as LaTeX';
|
|
icon: (Smalltalk ui icons iconNamed: #smallPrint);
|
|
action: [ self exportAsLaTeX ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Export as pdf';
|
|
icon: (Smalltalk ui icons iconNamed: #smallPrint);
|
|
action: [ self exportAsPDF ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'See html';
|
|
icon: (self iconNamed: #smallInspectIt);
|
|
action: [ self seeHtml ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'See pdf';
|
|
icon: (Smalltalk ui icons iconNamed: #smallInspectIt);
|
|
action: [ self seePdf ] ].
|
|
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Define debug message...';
|
|
icon: Smalltalk ui icons glamorousBug;
|
|
action: [ self defineDebugMessageUI ] ] ]
|
|
]
|
|
|
|
{ #category : #'event handling' }
|
|
GrafoscopioNewNotebook >> okToChange [
|
|
|
|
self isSaved ifTrue: [ ^ true ] ifFalse: [ ^ self askToSaveBeforeClosing ]
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> openDefault [
|
|
"I open a new default notebook"
|
|
|
|
^ self class new openWithSpec.
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> openFromFile: aFileReference [
|
|
self class registerRecent: aFileReference.
|
|
self loadFromFile: aFileReference.
|
|
^ self openWithSpec.
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> openFromFileSelector [
|
|
|
|
| file nb |
|
|
file := UIManager default
|
|
chooseExistingFileReference:'Choose a file'
|
|
extensions: #('ston')
|
|
path: FileLocator documents.
|
|
file ifNil: [
|
|
self inform: 'No file selected'.
|
|
^ self ].
|
|
self workingFile: file.
|
|
nb := self class new.
|
|
nb openFromFile: self workingFile.
|
|
GfUIHelpers updateRecentNotebooksWith: workingFile
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> openFromUrl: url [
|
|
"Opens a tree from a file named aFileName"
|
|
|
|
| fileName sanitized |
|
|
sanitized := GrafoscopioUtils sanitize: url.
|
|
fileName := sanitized segments last.
|
|
GrafoscopioUtils
|
|
downloadingFrom: sanitized
|
|
withMessage: 'Downloading document...'
|
|
into: FileLocator temp.
|
|
self class new openFromFile: (FileLocator temp / fileName)
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> openFromUrlUI [
|
|
"This method generates the UI for the openFromUrl: method, it asks for a URL from the user"
|
|
|
|
| fileUrl |
|
|
"GrafoscopioBrowser configureSettings."
|
|
fileUrl := UIManager default
|
|
textEntry: 'Enter the URL'
|
|
title: 'Open notebook from URL'.
|
|
fileUrl isNil ifTrue: [ ^nil ].
|
|
self class new openFromUrl: fileUrl
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
GrafoscopioNewNotebook >> pandocOptions [
|
|
^ self notebook pandocOptions
|
|
]
|
|
|
|
{ #category : #utilities }
|
|
GrafoscopioNewNotebook >> pandocOptionsComputed [
|
|
"I convert the pandoc options array into a single line that can be used with the pandoc command."
|
|
|
|
| result |
|
|
result := '' writeStream.
|
|
self pandocOptions ifNil: [ ^ '' ].
|
|
self pandocOptions
|
|
do: [ :option |
|
|
option isDictionary
|
|
ifTrue: [
|
|
self addCommandFrom: option into: result ]
|
|
ifFalse: [
|
|
result
|
|
nextPutAll: option] ].
|
|
^ result contents
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> pasteNodeFromClipboard [
|
|
tree selectedItem pasteFromClipboard.
|
|
self notebookContent: notebook.
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> pdfFile [
|
|
"I define the location of the markdown file where the notebook will be exported"
|
|
| pdfFile |
|
|
pdfFile := (self markdownFile parent fullName,'/', self markdownFile basenameWithoutExtension, '.pdf') asFileReference.
|
|
^ pdfFile.
|
|
|
|
]
|
|
|
|
{ #category : #initialization }
|
|
GrafoscopioNewNotebook >> projectSubMenu [
|
|
^ MenuModel new
|
|
addGroup: [ :group |
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Activate remote repository...';
|
|
icon: Smalltalk ui icons smallPushpinIcon;
|
|
action: [ self inform: 'To be implemented ...' ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Activate local repository...';
|
|
icon: Smalltalk ui icons homeIcon;
|
|
action: [ self inform: 'To be implemented ...' ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Add file...';
|
|
icon: Smalltalk ui icons newerPackagesAvailableIcon;
|
|
action: [ self inform: 'To be implemented ...' ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Delete file...';
|
|
icon: Smalltalk ui icons packageDeleteIcon;
|
|
action: [ self inform: 'To be implemented ...' ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Commit to repository';
|
|
icon: Smalltalk ui icons smallScreenshotIcon;
|
|
action: [ self inform: 'To be implemented ...' ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Credentials';
|
|
icon: (self iconNamed: #userIcon);
|
|
action: [ self inform: 'To be implemented ...' ] ] ]
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> promoteNode [
|
|
| editedNote |
|
|
editedNote := tree selectedItem.
|
|
editedNote promote.
|
|
self notebookContent: notebook
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> removeNode [
|
|
| contentToDelete parentContent newSelectedContent children path |
|
|
tree selectedItem
|
|
ifNil: [ ^ self inform: 'No node available or properly selected ' ].
|
|
|
|
path := tree selection selectedPath.
|
|
contentToDelete := tree selectedItem.
|
|
contentToDelete shouldAskBeforeRemove
|
|
ifTrue: [ (UIManager default
|
|
questionWithoutCancel:
|
|
'The selected node has children and / or content. This change so far cannot be undone. Are you sure you want to proceed? '
|
|
title: 'Remove node')
|
|
ifFalse: [ ^ self ] ].
|
|
parentContent := tree selectedItem parent.
|
|
children := parentContent children.
|
|
children size > 1
|
|
ifTrue: [ children last = contentToDelete
|
|
ifTrue: [ newSelectedContent := children at: children size - 1 ] ]
|
|
ifFalse: [ newSelectedContent := parentContent ].
|
|
contentToDelete parent removeNode: contentToDelete.
|
|
self notebookContent: notebook.
|
|
self resetSelectedItemTo: path.
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> resetSelectedItem [
|
|
tree selectedIndex: (tree selectedIndex min: notebook children size).
|
|
tree highlightedItem: tree selectedItem.
|
|
tree updatePresenter.
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> resetSelectedItemTo: aPath [
|
|
tree selectPath: {(aPath first min: notebook children size)}.
|
|
tree updatePresenter
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> saveToFile: aFileReference [
|
|
"I save the current tree/document to a file and update storage timestamp."
|
|
|
|
aFileReference ifNil: [ self inform: 'No file selected for saving. Save NOT done.'. ^ self ].
|
|
workingFile := aFileReference.
|
|
self workingFile ensureDelete.
|
|
self workingFile writeStreamDo: [:stream |
|
|
self exportAsSton: self notebook on: stream ].
|
|
self title: self workingFile basenameWithIndicator, ' | Grafoscopio notebook'.
|
|
self inform: ('File saved at: ', String cr, self workingFile fullName).
|
|
GfUIHelpers updateRecentNotebooksWith: aFileReference.
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> saveToFileUI [
|
|
|
|
| file |
|
|
|
|
file := UIManager default
|
|
chooseForSaveFileReference: 'Save notebook to file as...'
|
|
extensions: #('ston')
|
|
path: (workingFile ifNotNil: [ workingFile parent ] ifNil: [ FileLocator documents ] ).
|
|
file
|
|
ifNil: [ self inform: 'Saving to file cancelled'. ^ self ]
|
|
ifNotNil:[self saveToFile: file].
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> saveWorkingNotebook [
|
|
"Saves the current tree to the user predefined file location used when he/she opened it."
|
|
self workingFile
|
|
ifNil: [ self saveToFileUI ]
|
|
ifNotNil: [ self saveToFile: workingFile ].
|
|
self notebook root updateEditionTimestamp.
|
|
GfUIHelpers updateRecentNotebooksWith: workingFile
|
|
|
|
|
|
]
|
|
|
|
{ #category : #inspecting }
|
|
GrafoscopioNewNotebook >> seeHtml [
|
|
self pdfFile exists
|
|
ifTrue: [ (#open command argument: self htmlFile fullName) schedule ]
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> seePdf [
|
|
self exportAsPDF
|
|
onSuccessDo: [ :v | (#open command argument: self pdfFile fullName) schedule ]
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> selectedItem: anItem [
|
|
tree selectItem: (tree roots detect: [ : p | p = anItem ]).
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> subtreeAsMarkdown [
|
|
| currentNode |
|
|
currentNode := tree selectedItem.
|
|
self inform: ('Exported as: ', String cr, (self subtreeAsMarkdownFileFor: currentNode) fullName )
|
|
]
|
|
|
|
{ #category : #persistence }
|
|
GrafoscopioNewNotebook >> subtreeAsMarkdownFileFor: aNode [
|
|
| exportedFile |
|
|
aNode links ifEmpty: [ ^ self ].
|
|
exportedFile:= self navigateRelativePathFor: aNode links last.
|
|
exportedFile class = self class ifTrue: [ ^ self ].
|
|
self exportNode: aNode asMarkdownIn: exportedFile.
|
|
^ exportedFile
|
|
]
|
|
|
|
{ #category : #'editing nodes' }
|
|
GrafoscopioNewNotebook >> toggleCodeNode [
|
|
| currentNode |
|
|
currentNode := tree selectedItem.
|
|
currentNode toggleCodeText.
|
|
self updateBodyFor: currentNode
|
|
]
|
|
|
|
{ #category : #initialization }
|
|
GrafoscopioNewNotebook >> topBar [
|
|
^ SpMenuBarPresenter new
|
|
addGroup: [ :group |
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Notebook';
|
|
icon: (self iconNamed: #smallObjects);
|
|
subMenu: self notebookSubMenu ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: 'Project';
|
|
icon: (self iconNamed: #catalog);
|
|
subMenu: self projectSubMenu ] ];
|
|
addGroup: [ :group |
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Save notebook';
|
|
icon: (self iconNamed: #glamorousSave);
|
|
action: [ self saveWorkingNotebook ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Export all Markdown subtrees';
|
|
icon: (self iconNamed: #glamorousMore);
|
|
action: [ self exportAllSubtreesAsMarkup ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Cut';
|
|
icon: (self iconNamed: #smallCut);
|
|
action: [ self cutNodeToClipboard ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Copy';
|
|
icon: (self iconNamed: #smallCopy);
|
|
action: [ self copyNodeToClipboard ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Paste';
|
|
icon: (self iconNamed: #smallPaste);
|
|
action: [ self pasteNodeFromClipboard ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Find & Replace';
|
|
icon: (self iconNamed: #smallFind);
|
|
action: [ self findAndReplace ] ] ];
|
|
addGroup: [ :group |
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Add node';
|
|
icon: MendaIcons new plusIcon;
|
|
action: [ self addNode ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Delete node';
|
|
icon: MendaIcons new minusIcon;
|
|
action: [ self removeNode ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Move node up';
|
|
icon: MendaIcons new arrowUpIcon;
|
|
action: [ self moveSelectedNodeUp ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Move node down';
|
|
icon: MendaIcons new arrowDownIcon;
|
|
action: [ self moveSelectedNodeDown ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Move node left';
|
|
icon: MendaIcons new arrowLeftIcon;
|
|
action: [ self promoteNode ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Move node right';
|
|
icon: MendaIcons new arrowRightIcon;
|
|
action: [ self demoteNode ] ] ];
|
|
addGroup: [ :group |
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Toggle: code <--> text';
|
|
icon: MendaIcons new smalltalkCodeIcon;
|
|
action: [ self toggleCodeNode ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'List node links';
|
|
icon: (self iconNamed: #tinyMenu);
|
|
action: [ self linksList ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Visit link';
|
|
icon: (self iconNamed: #glamorousRight);
|
|
action: [ self visitNodeLink ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Import link content';
|
|
icon: (self iconNamed: #glamorousOpenFromUrl);
|
|
action: [ self importLinkContent ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Export link content';
|
|
icon: (self iconNamed: #glamorousSaveToUrl);
|
|
action: [ self exportLinkContent ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'HTML to Markdown';
|
|
icon: (self iconNamed: #smallProfile);
|
|
action: [ self htmlToMarkdown ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'HTML to Markdown subtree';
|
|
icon: (self iconNamed: #hierarchy);
|
|
action: [ self htmlToMarkdownSubtree ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Tag as...';
|
|
icon: MendaIcons new tagAddIcon;
|
|
action: [ self inform: 'To be implemented...' ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Untag ....';
|
|
icon: MendaIcons new tagMinusIcon;
|
|
action: [ self inform: 'To be implemented...' ] ].
|
|
group
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Edit tags...';
|
|
icon: FontAwesomeIcons new tagsIcon;
|
|
action: [ self inform: 'To be implemented...' ] ] ];
|
|
addGroup: [ :debug |
|
|
debug
|
|
addItem: [ :item |
|
|
item
|
|
name: '';
|
|
description: 'Debug';
|
|
icon:
|
|
(self iconNamed: #glamorousBug);
|
|
action: [ self debugWithSelector: self debugMessage ] ] ]
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> tree [
|
|
^ tree
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> tree: anObject [
|
|
tree := anObject
|
|
]
|
|
|
|
{ #category : #operation }
|
|
GrafoscopioNewNotebook >> updateBodyFor: aNode [
|
|
self needRebuild: false.
|
|
tree needRebuild: false.
|
|
body needRebuild: true.
|
|
aNode openIn: self.
|
|
self buildWithSpec
|
|
]
|
|
|
|
{ #category : #operation }
|
|
GrafoscopioNewNotebook >> visitNodeLink [
|
|
tree selectedItem visitLastLink
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> windowMainMenu [
|
|
^ windowMainMenu
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> windowMainMenu: anObject [
|
|
windowMainMenu := anObject
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> workingFile [
|
|
^ workingFile
|
|
]
|
|
|
|
{ #category : #accessing }
|
|
GrafoscopioNewNotebook >> workingFile: aFileReference [
|
|
workingFile := aFileReference.
|
|
]
|
|
|
|
{ #category : #'as yet unclassified' }
|
|
GrafoscopioNewNotebook >> wrapBodyLines [
|
|
self currentNodeContent wrapBodyLines.
|
|
self updateBodyFor: self currentNode
|
|
]
|