a feasibility study for a general-purpose visual ... · research in computer science ii spring 2010...
TRANSCRIPT
Research in Computer Science IISpring 2010
A feasibility study for a general-purposevisual programming system
Dimitar Asenov
Supervisor: Peter Muller
19th July, 2010
Contents
1 Introduction and Motivation 4
2 Related work 5
2.1 Visual programming languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Visualization techniques and interaction tools . . . . . . . . . . . . . . . . . . . . . 6
2.3 Visualization evaluation and experiments . . . . . . . . . . . . . . . . . . . . . . . 7
3 The Envision system 8
3.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.2 Source code representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.2.1 Visualization principles of Envision . . . . . . . . . . . . . . . . . . . . . . . 10
General-purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Efficient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Fast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Intuitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Flexible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Focused . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Appropriate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Self-sufficient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Varied . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Friendly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2.2 Entity visualizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3 User interaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.3.1 Construction of visuals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.3.2 Giving commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.4 Use case examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.4.1 Programming a Hello World application . . . . . . . . . . . . . . . . . . . . 15
3.4.2 Visualizing the source code of Envision itself . . . . . . . . . . . . . . . . . 18
3.5 Case study: call stack visualization . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4 Discussion 19
4.1 Implementation of the visualization principles . . . . . . . . . . . . . . . . . . . . . 20
4.1.1 General-purpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.1.2 Efficient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.1.3 Fast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.1.4 Intuitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2
4.1.5 Flexible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.1.6 Focused . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.1.7 Appropriate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.1.8 Self-sufficient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.1.9 Varied . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.1.10 Friendly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.2 Comparison to traditional programming environments . . . . . . . . . . . . . . . . 22
4.2.1 Productivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.2.2 Readability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.2.3 Navigation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.2.4 Maintainability (Viscosity) . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.2.5 Teaching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5 Future work 23
6 Conclusion 24
3
Abstract
As electronics and computers become an ever-bigger part of our life there is a growing needfor creating higher-quality software faster. Visualizing the structure, execution and model ofprograms can improve the development process. Numerous methods and styles exist for visualizingdifferent software artifacts but, despite previous efforts, visual programming has only very limiteduse in industrial organizations. We present Envision - a framework for general-purpose visualprogramming. It combines many existing techniques with novel ideas to increase productivity andcode comprehension. It aims to support visual programming for large scale industrial projects ina wide variety of domains.
1 Introduction and Motivation
Throughout the history of computer science many new programming languages have been de-veloped. This is hardly surprising given the fact that computational devices are playing an evergreater role in our life. The increasing variety and power of computers present a challenge to exist-ing software solutions. To better manage the complexity of growing applications it is necessary todevelop new ways to program. There can be many driving goals when creating a new language: tomake it easier to learn how to program, to introduce support for a new programming paradigm orhardware feature, to make it very efficient, etc. However, languages alone can no longer cope withlarge-scale development tasks. To alleviate the problem there is a continuing effort to improve theintegrated development environments (IDEs) that provide a platform around a language to makeit easier to create and navigate a big programming project.
During all these developments one thing has remained constant - programming languages aretextual. The programmer creates a program by writing its source code. In the process, differentprogram structures and modules are saved to different files or folders. The source code, writtenusing a precise grammar, fully defines the structure and behavior of the program. This poses anumber of important restrictions:
• The developer must learn and use a very specific language syntax. This often includes ruleswhich are not intuitive for novice programmers. Even experienced programmers might findit difficult or cumbersome to use these rules (e.g. when writing scripts in the Bash scriptinglanguage).
• Creating new programing elements and navigating existing ones relies mostly on symbolicreasoning and memory.
• Additional resources required for developing bigger projects such as documentation, dia-grams, etc. are separate from the source code. They help the programmer write the applica-tion, but do not have a direct influence on it and are not linked to program elements. Thiscauses inconsistencies when only the code or the documentation is modified.
• Getting familiar with a larger software base by only looking at its source code is an over-whelming task. To make this possible one refers to the supporting documentation, since thesource code itself does not guide the programmer in how to explore the application.
While modern IDEs help to reduce the impact of these restrictions they can not remove themsince these restrictions are inherent to textual representations.
In an effort to truly remove some of these drawbacks researches have experimented with visualprogramming languages. Some of the advantages that they found when using visual representationsare:
4
• Visual objects can more directly map to programming entities, removing the need for com-plicated syntax. Thus it is easier for novice programmers to learn to use such a language.Experienced programmers can also benefit from this and be more productive.
• Visual programming involves not only symbolic, but also visual and spatial cognitive pro-cesses. This can improve both the comprehension and retention of programs as the graphicalrepresentations more closely match a programmer’s mental model. Studies [1, 2] have shownthat retention for visual images is better compared to that for text.
• Two dimensional graphical representations can be more expressive compared to text whichuses a single dimension.
• Figures, diagrams, tables and such, can be directly embedded in a visual program and makeit easier to understand and explore.
Intuitively visual representations can help better organize a programming activity.
Despite previous efforts to develop visual languages, the term programming is still commonlyassociated with writing source code. The top 20 languages used in industry in June 2010 accord-ing to the popular ranking site TIBOE 1 are all textual. Other on-line rankings for languagesyield similar results. While the initial hopes for visual languages were high, they did not meetresearchers’ expectations. Meanwhile research focus has shifted away from visual programming tosoftware visualization and end-user programming.
We propose a new take on visual programming. Learning from the lessons of previous researchand developing for today’s powerful hardware we have established the concept of Envision - ageneral-purpose visual programming system. The goals we set to achieve include developing ahighly flexible visual programming environment, that easily scales to large programming projectswhile improving the developer’s experience and performance compared to modern IDEs. Thispaper reports on an initial study designed to asses the feasibility of our approach.
Section 2 explores related work in the fields of visual languages, software visualization and human-computer interaction. Next, the main ideas behind the visualization and user interaction inEnvision are presented in section 3. The subsequent section 4 assesses the performance of ourapproach compared to existing programming techniques. In section 5 we report on our plans forfurther development of the system. Finally we summarize our findings in section 6.
2 Related work
2.1 Visual programming languages
Many visual programming languages (VPLs) have been developed in the past. Schiffer and Frohlichdesigned Vista[3] - a VPL which builds on top of the object-oriented programming (OOP) paradigmand aims to provide support for high-level building blocks and ease of use. At the more abstractlevel, programming in Vista involves building entities and networks between components in avisual environment. A central notion in the language is the processor which is a logical unit in theprogram that has a distinct function. Processors are somewhat similar to classes and communicatewith each other via data and signal tokens. Different processors can be connected to each otherusing a graphical user interface (GUI). In the GUI each processor is represented by an icon. Atthe lower level of abstraction Vista provides access to the full Smalltalk library and allows writingcode fragments using text.
Another tool for visual programming is Seity[4]. It is a visual environment for the Self programminglanguage. Seity represents objects as three-dimensional boxes that list an object’s properties and
1http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
5
methods. An important concept for the environment is the focus on objects, rather than views.Each object is unique and appears at most once on the screen but an object can present differentviews of itself based on the current needs of the programmer. Chang and his colleagues arguethat this makes it easier for the programmer to maintain object identity which is not the casewith view-focused IDEs. They propose that manipulating the object directly and not through anintermediate view, makes the objects concrete and tangible. On the other hand using tools suchas class browsers or object inspectors makes the objects seem secondary and distant.
Citrin et al. in [5] propose VIPR - an entirely new approach to programming based on visuallynesting circles. A program in VIPR would be represented by a circle that consists of a series ofnested circles, representing statements, classes, methods, etc. The execution proceeds by perform-ing the statement connected with the outer-most circle and removing that circle. More complicatedexecution traces can be created by connecting different circles with arrows which indicate the nextstatement and possibly have an associated condition. An advantage of VIPR is that each state ofa program at run-time is itself a valid VIPR program - the same language is used for programmingand execution visualization.
Another entirely visual approach to writing object-oriented programs is using Prograph[6]. Classesin Prograph are represented by icons and so are each class’ fields and methods. A method isdefined visually by connecting various types of entities together using arrows. Entities includeinputs, outputs, function calls, constants, variables, object instances, etc. Prograph comes with afully featured environment that allows the user to explore the program using various views. Thisincludes structure visualizations, class diagrams, property explorers and others.
More recently Grant has designed Visula[7]. The key idea behind Visula is the use of UML-likesequence diagrams to define program behavior. The diagrams are extended with control-flow andclass definition elements. Since UML-diagrams are used by many professionals such an approachhas the benefit of being familiar to experts.
Most VPLs are short-lived and rarely get much attention outside of research circles. One notableexception is National Instruments’ LabView. It is a visual data-flow language specifically designedfor data acquisition, analysis and instrument control and automation. Applications represent in-struments. Each application has a virtual front panel where the user can interact with a widevariety of controls: buttons, knobs, displays, light emitting diodes etc. The logic of the applica-tion is defined by its back panel where different processing elements can be connected to definethe data flow. A processing element can be an entire instrument, a built-in library function, anarithmetic or string operation, etc. Flow control entities such as loops and conditionals are alsoincluded. Programming in LabView is mostly done using the mouse, by dragging and droppingcomponents from a palette onto the instrument panel and connecting them using wires. In [8],Baroth and Hartsough report on their experience with the language at the Jet Propulsion Labo-ratory, California Institute of Technology under a contract with the US National Aeronautics andSpace Administration. The same software system was developed simultaneously in both LabViewand C. The two teams were given identical budget and deadlines to come up with a solution. Theteam using LabView managed to cover and significantly exceed the requirements of the softwarewhile maintaining constant contact with the customer. The team using C did not further com-municate with the customer after receiving the initial requirements and did not make a productthat fully meets them. Our personal experience with LabView in designing automated tests isalso very positive. However LabView is not very well suited for general purpose programming. Inparticular its aim at data-flow programming makes it harder to model more reactive systems. Itssupport for OOP principles is also limited.
2.2 Visualization techniques and interaction tools
Although the hope had been high that VPLs would bring a revolution in programming, thiswas not the case. Nevertheless developers realized that visualizations can indeed improve the
6
software development process. Thus many tools were created which instead of substituting textualprogramming, complement it with visual representations. They have enjoyed a much higher successand adoption rate in industrial environments.
Major efforts in visualization tools are often implemented in new versions of popular IDEs oras IDE extensions. Modern programming environments come with color coded language syntax,auto-completion tools, code snippet libraries, UML diagram generators, etc.
The Human Interactions in Programming 2 group at Microsoft Corporation continuously eval-uates new ways to improve the usability of Microsoft’s Visual Studio IDE. Among others theyhave investigated the effect of presenting code usage information directly in the IDE to improvenavigation[9, 10]; why and how software developers use graphics and whether these needs can bemet by embedding images directly in the IDE[11]; improving navigation by visualizing code withautomatically generated maps[12] or displaying code-thumbnails of files[13].
Being an open-source tool with a strong community and industrial support the Eclipse3 IDE hasalso enjoyed a lot of attention from researchers. One of the more popular extensions developedfor Eclipse is Shrimp[14]. It can visualize various aspects of Java code including class hierarchies,packages or individual classes. Additionally it has support for showing associated documentationand navigating around the different elements. Going one step further is CodeBubbles[15, 16] byBragdon et al. This tool uses Eclipse only as a back-end and presents the user’s code in a newenvironment that features a visual representation of code based on a bubbles metaphor. A class, amethod, a JavaDoc snippet or even custom notes can be displayed in an independent frame - thebubble. Each bubble is a text editor in itself. Many bubbles can be shown on the screen and theprogrammer can arrange them in any way she prefers. This helps with task oriented programmingactivities such as debugging and maintenance.
Another interesting extension for Eclipse, that focuses on user input is Quack[17]. It allows theuser to program ”sloppily” by entering keywords instead of proper statements. Quack would thentry its best to determine the programmer’s true intent and create the corresponding statements.
2.3 Visualization evaluation and experiments
Whitely has compiled an overview of VPLs in [18]. It is immediately evident that there areonly a few quantitative experiments that asses the viability of visual programming. Whitleyconcludes that no program representation (textual or visual) is better in absolute terms. Somerepresentations yield better results in specific tasks, while other representations in others. It isimportant that the task at hand and the chosen representation match well. Further observationswere that for smaller programs text might be a preferred option and that special attention shouldbe paid to how well screen estate is utilized by visual representations. In the end visuals are said toimprove the programming experience but there are not enough experimental studies or sufficientcognitive theories to guide the design of VPLs.
The classic Cognitive Dimensions(CD) framework by Green and Petre[19] has been often used toevaluate the design of a new VPL. Their work suggests a number of criteria by which a program-ming language and its environment can be evaluated. Initially they applied their framework tothree languages: FORTRAN, Prograph and LabView. They found that generally the construc-tion of visual programs is easier because there are less syntactic hassles and because of the useof higher-level operators. They also identified several problems with visual programming thatneed to be addressed: clutter, insufficient screen real-estate and high viscosity (resistance to localchange of programs).
2http://research.microsoft.com/en-us/groups/hip/3http://www.eclipse.org/
7
3 The Envision system
The purpose of this feasibility study is to introduce and evaluate the visualization and user inter-action concepts of Envision. However the overall plan for the Envision system goes beyond this.To provide a better insight of the context of this study we will first present the full set of featuresplanned for Envision. Afterwards we elaborate on the visualization and interaction parts of thesystem including demonstrative examples.
3.1 Overview
The concept for Envision is a combination of an IDE and an information system. Like a typical IDEEnvision allows programmers to create software and aids in this process in various ways. Actingas an information system Envision maintains the software’s repository, including all supportingdocumentation, graphs, tables etc. and keeps these development artifacts in a consistent state.Here is a list of the most distinguishing features in both domains:
IDE:
• Visual source code representation - the programmer does not work purely with text, butrather interacts with a visual representation of the program. The visualization also includestext in order to achieve maximum flexibility.
• Command enabled user interaction - apart from standard means of input, the user can alsoissue commands to the system in a style similar to an operating system shell. These com-mands are dependent on the currently selected program entity and can represent arbitraryoperations such as constructing new program elements, conducting searches, invoking a newprocess or running system commands.
Information system:
• Semantic versioning - unlike traditional file-based version control systems Envision storesversions of programming entities like classes, methods, fields etc. This allows for bettertracking of software evolution and enables new analysis techniques.
• Content linking - a program will not be just the instructions it executes but will also con-tain all supporting development artifacts. Figures, animations, tables or documents can beembedded directly in the software project. Moreover links can exist between different typesof content to keep the application in a consistent state. For example the value of a constantcan be taken from a table in the document describing its meaning and computation.
• Continuous analysis - the Envision system will continuously analyze the software in the back-ground. This involves activities such as automatic test-case execution, formal verificationand collection of statistics. This information will be reported to the user directly embeddedin the visual representation of the software to aid with the development process.
Envision is primarily aimed at large-scale software development. While we also consider beginners,the main target users are expert programmers. The system is meant to be a general purpose IDEthat can be used to efficiently build a wide variety of software. To this end it should also supportthe more popular programming paradigms. In developing the concept for Envision we strive tomaintain a positive answer to these questions:
• Would we want to use this system every day for our coding needs?
• Can we efficiently build different kinds of software with it?
8
• Could we use it to create large-scale software products such as an operating system?
• Does the system feel familiar and intuitive for experienced programmers?
• Is it fun and easy to work with?
Our hypothesis is that the combination of these features in an integrated system is very powerful.The work in this feasibility study represents the first step towards testing our designs. Oncethe system is more mature we plan to conduct quantitative studies to objectively evaluate thefulfillment of the above criteria.
It is important to note that at the moment Envision is still in design phase and only a few featureswere implemented as part of this study. These are discussed next.
3.2 Source code representation
Despite the large number of visualization techniques developed by researches there is a lack ofquantitative experiments that allow us to set rules for what are good software visualizations andwhat are not[18]. A few works exist that try to establish some guiding principles for creatingvisual languages. Here we will briefly discuss two that have helped guide our effort.
Green and Petre developed the classical Cognitive Dimensions framework[19]. It provides re-searches with a means to evaluate their designs. Originally the framework was applied to onetextual and two visual programming languages. In our work we have applied Green and Petre’sfive conclusions regarding future work in VPL design:
1. Reduced syntactic load and higher-level operators. Building a program visually reduces theneed to remember and use precise syntax rules common for textual languages. Visual source-code representations allow for higher-level operations to be expressed concisely. These fea-tures increase the concentration of the programmer.
2. Improved secondary notation. The capabilities of modern graphics hardware have come along way since the Cognitive Dimensions framework was conceived. Envision uses a broadspectrum of visual capabilities in order to improve secondary notation in programs. Thisincludes colors, shapes, shadows, translucency, visual effects, visual transformations, icons,animations, grouping, modularizing and others.
3. Familiar control-flow representation. In Envision control flow statements have received avisual overhaul but remain structurally close to what programmers are used to in traditionallanguages.
4. Low viscosity. Unlike many previous efforts to design a VPL, an explicit goal for Envision isto be at least as productive as text-based environments with respect to writing or modifyingcode. We hope to achieve this by relying heavily on keyboard based input for the IDE. Theinput mechanisms of Envision are discussed in detail in section 3.3.
5. Better utilization of screen real-estate. Although it is quite a different concept Envisionresembles CodeBubbles[15, 16] when it comes to how the screen can be utilized to showsoftware fragments. CodeBubbles has been shown to increase the number of function codevisible on the screen by about 50% in the typical case. We hope to achieve similar results.
More recently, Petre has analyzed four previous studies on the mental imagery that expert pro-grammers use[20]. She also summarizes lessons learned about characteristics of good visualiza-tions. Her work has helped shape the guiding principles(3.2.1) of the visualization component inEnvision.
9
3.2.1 Visualization principles of Envision
Here we list the major design principles that have shaped the initial software representations ofEnvision. We also provide the rationale behind them.
Software visualization in Envision should be . . .
General-purpose Envision is meant to be employed in a wide variety of domains. The visual-ization component should match this goal.
• Many domain-specific VPLs exist and some also enjoy success in industrial settings[21, 22,23]. However, for general-purpose applications, purely textual languages like Java, C#, C,C++, Visual Basic, PHP, Python and their text-based IDEs dominate the market. We wantto promote visual programming in this segment.
Efficient The system should allow the programmer to be at least as effective in constructingsoftware as text-based IDEs.
• There is little incentive to switch to a new type of IDE if it does not provide tangible benefits.We feel that past efforts to introduce visual programming have often failed to deliver enoughwith respect to programmer productivity. One of the core reasons for developing Envisionis to offer a platform that ultimately improves the programming experience.
Fast The system should be highly responsive to the user.
• Computing a complicated visual scene has the potential to reduce the computer’s respon-siveness to user input. This is not acceptable for Envision which wants to compete withtext-based IDEs where there is no such problem. The performance of modern graphicshardware should be utilized to deliver an optimal user experience.
Intuitive The programmer should find it easy to use our environment. Visualizations shouldlook familiar and perform as expected.
• Two important aspects hinder the adoption of new tools - unfamiliarity and unconventionalbehavior. More often than not, past VPLs were not successful in penetrating the commercialmarket because they required completely new programming paradigms. Consequently anybenefits they offered were outweighed by the complexity of learning how to use or interpretthem. Envision is based on OOP - a programming paradigm that has stood the test of timeand has proven to be exceptionally versatile. A programmer should be able to work withthe system with a minimal introduction. Where appropriate Envision might provide hintsto the user of how to use novel features.
Flexible The visuals in the system should be flexible to display as much detail or as higher-level of abstraction as needed. Their flexibility should at a minimum match the one of textualrepresentations. It should also be possible to create new views and tools through plug-ins.
• In their every day job programmers face a variety of tasks. A good tool should be able toprovide the necessary level of abstraction to quickly navigate and understand software. Ifa tool is too narrow in its selection of views or detail level it will, at best, only be usedfor specific purposes. This is unacceptable for a general-purpose IDE targeting large-scaledevelopment projects.
10
Focused Visual support should be focused on the task at hand and on the immediate needs ofthe programmer. Unnecessary tools or options should not be visible.
• In popular IDEs such as Eclipse or Microsoft Visual Studio there are a lot of different tools,buttons and menus visible by default. For the most time however a programmer does notneed them. Showing those tools on the screen contributes little to the programming taskat hand when they are not needed. Instead screen real-estate can be better utilized bydisplaying more of what the user is actually working on - be it a software fragment or adocument.
Appropriate The representations of software entities should match the nature of the representeddata.
• One of the major outcomes of Whitley’s analysis of empirical studies about VPLs[18] isthat visuals perform poorly when they are not suited to the entity they represent. It isvital to carefully choose what visualizations to use in which cases. Equally important isto be able to say no to a graphic when a few simple lines of text feel much more natural.Envision combines visuals with text in an effort to deliver an optimal experience for variousprogramming elements.
Self-sufficient No other tool should be needed to design large-scale software. In particular nostand-alone textual editors should be used.
• Envision should provide enough support and levels of abstraction to cover the entire rangeof developer needs. Even accessing more complicated features such as memory alignmentdeclarations or special CPU instructions should be achievable from within the IDE.
Varied The looks of the IDE should take advantage of modern hardware and offer a wide varietyof visual cues and styles.
• Limited by hardware performance the VPLs of one or two decades ago could not look asappealing and polished as it is possible nowadays. It is essential to exploit the full capabil-ities of modern hardware to deliver a fully immersing programming experience. Secondarynotations would also benefit from this.
Friendly Envision should be fun to use. It should just ’feel right’.
• If the programmer thinks a tool is hard to use he or she will find alternatives to replace it.This is especially true of a new IDE that someone is considering for future use. Envisionshould be characterized by a natural and inviting interface. Only then will it be consideredfor serious software development.
3.2.2 Entity visualizations
On the higher abstraction level the visualization of software in Envision is based on boxes orblocks. These are used to display entities such as applications, modules, classes and methods.More detailed levels of software fragments such as method statements or class fields are specifiedin textual format. Figure 1 shows a basic hello world application. The outer-most box is theapplication. It contains modules which are similar to packages in Java. In this case there is
11
text string
main
text = "Hello World!"print(text)
HelloAppMain
HelloApp
Figure 1: A Hello World application.
only one module - Main. The module’s color and the position of the module boxes within theapplication is determined by the programmer.
A module contains classes. The Hello World application has only one class - HelloApp. Classesare indicated by an icon resembling a class hierarchy. The background color of each class is slightlytransparent so that a user working on a bigger class can identify the module it belongs to. Theuser determines the position of a class within the enclosing module.
A class contains fields and methods. Figure 2 shows the representation of a simple circle class. Thebox in the upper left corner of the class shows defined fields. They are split into three categories inthree columns - from left to right: public, protected and private. The Circle class has a booleanfield filled which is public and three private fields: x, y and radius.
Methods within a class are also contained in boxes. These boxes have a white background toimprove readability and can be manually placed anywhere in the class. The Circle class has twomethods. A method is indicated by an icon depicting two gears and its name. Furthermore onthe right of the name a box with the method arguments appears. There the type of an argumentappears under its name. A method contains a sequence of statements. As we can see from thearea method these statements are not limited to plain text but can include special symbols,graphics, formatting, effects, etc. Currently Envision only supports textual statements with a fewexceptions (discussed below). We plan to extend this further. For example special symbols and
x inty intradius float
filled boolean
translate dxint
dyint
x += dxy += dy
area
return π·radius²
Circle
Main
HelloApp
Figure 2: A simple Circle class.
12
graphics will be used to indicate assignments, function calls, recursive functions, matrices, returnstatements and others.
Control structures are a special case of statements. Envision currently has custom visualizationsfor if-else statements and loops. Figure 3 shows a factorial method that includes control statements.An ’if’ control statement is indicated by a yellow diamond icon. Next to it is the condition. Below
factorial nint
n < 1
return 1 int result = 1
int i = 1; i < n; i++
result *= i
return result
CircleMain
HelloApp
Figure 3: Control statements in a factorial function.
this horizontally arranged are the ’then’ and ’else’ branches indicated by light green and redbackground colors respectively. A ’loop’ is indicated by an icon with rotating arrows and a specialborder. Next to the icon is the header defining the loop including terminating or continuingconditions.
As we’ve seen above visual abstractions exist for higher-level language features while specificdetails and execution statements are presented textually. However we find that adding additionalvisual effects or hints can be helpful even for text-based information. The reader might also noticethat there are hardly any keywords visible. This is because the concepts that keywords embodyare often better represented visually. For instance we can use color and/or position to indicatesemantics. The structure of the ’if-else’ statement and the fields of a class are good examples forthis.
3.3 User interaction
In order to improve programming productivity and appeal more to expert programmers input inEnvision is mostly from the keyboard. In the current implementation the mouse is only used tozoom in and out using the wheel and to move visual objects. The programmer can simply clickanywhere on an object and drag it to a different position. One exception is clicking on a piece oftext which displays the text editing cursor instead. Mimicking text-based IDEs all text visible onthe screen is editable directly.
The two major features that define the feel of the user input system are discussed next.
3.3.1 Construction of visuals
Visual objects in Envision are not drawn or chosen from a palette. Instead they are constructedby typing. For example to create a new class the programmer would type ’class MyNewClass’ andpress Enter. This will create a new class within the currently selected module. The class name willbe set to ’MyNewClass’. The class will be selected and ready to receive input. The programmercan then proceed to add methods or fields in a similar fashion using the keyboard. Whenever anew entity or statement is added its parent automatically expands to fully include it.
More complicated structures are also created from the keyboard. Typing ’if condition’ will create
13
a new if statement with the specified condition. Figure 4 shows this process. Similarly typing’for header ’ will create a new for loop with the specified header. This is illustrated in figure 5.Moreover it is possible to create statements based on the current context. For instance if thecurrently visible scope contains an integer variable named ’count’ and the user types ’for count’the system would automatically generate a for loop that counts from 0 to count - 1. As a countingvariable the first non-used of i, j, k, l,m, ... will be used. This is demonstrated in figure 6.
abs valint
asdftest
he
(a) Waiting for input
abs valint
if val < 0
asdftest
he
(b) Typing a cre-ation command
abs valint
val < 0
asdftest
he
(c) An if statement iscreated
Figure 4: Creating an if statement.
countdown topint
for int i = 0; i<top; i++
aa
a
(a) For loop command
countdown topint
int i = 0; i<top; i++
aa
a
(b) Resulting statement
Figure 5: Creating a for loop by specifying the complete header.
The concept behind this mechanism is the separation between what the user types and what theapplication fragments look like. In traditional IDEs and programming languages the programmerdirectly writes the final structure of the software. This has the drawback that a specific grammarmust be learned and used. Such a grammar typically contains many syntactical rules, symbols,delimiters, etc. This is not very convenient but is necessary in order for the parser to be able tounderstand the language and in order for the language to stay compact. In Envision syntax is keptto a minimum. The programmer expresses her desires by commands which the IDE interprets.It is responsible for figuring out what exactly the user means and for creating the corresponding
sumall elementsint[ ]
sizeint
int sum = 0for size
aa
a
(a) For loop command
sumall elementsint[ ]
sizeint
int sum = 0
int i = 0; i<size; ++i
aa
a
(b) Resulting statement
Figure 6: Creating a for loop by specifying just the counting variable.
14
software fragment. This reduces the complexity of what needs to be typed especially with respectto syntax. At the same time concreteness is maintained - the visual result has a precise meaning.
3.3.2 Giving commands
By right-clicking anywhere on the screen the user shows a command prompt. It is used to quicklyperform a variety of tasks which are dependent on the context:
• Create new software entities such as modules, classes, methods, fields, etc.
• Invoke IDE functions such as searching, opening views or projects and others.
• Execute system commands like copying files or playing the next song in your audio player.
• Perform user-defined actions.
The context of a prompt depends on where the programmer has clicked. After the user types acommand it will be passed to the entity defining the context. This could be for example a methodor a class. If the current context can not understand the command it is propagated to its parent.This process continues until some entity knows how to handle the command. If there is no suchentity an error message appears directly under the prompt.
Figure 7 shows how to create a new class. The use has right-clicked on the translate method.A method does not understand the ’class’ command and will pass it to its parent - a class. Aclass also does not understand this command and will propagate this to its enclosing module. Themodule interprets the class command by creating a new class with the specified name.
If the context was the Application object itself, the command would fail since an Application doesnot know the ’class’ command. This is depicted in figure 8. Providing a wrong command wouldalso result in a similar error message.
This prompt provides great flexibility at the programmer’s fingertips. Common IDE functions canbe invoked directly without opening menus or dialogs. Entire software fragments can easily bebuilt by typing a single line.
3.4 Use case examples
3.4.1 Programming a Hello World application
Here we will see how to create a Hello World application step-by-step. After starting Envision anempty canvas appears with a prompt in the middle. Type the following commands:
1. app HelloWorld - creates a new application called HelloWorld.
2. module Main - creates the Main module within the application.
3. class Hello - creates a new class within the module.
4. method main - creates the main method of the class.
5. print "Hello World!" - the only statement of our program.
Notice how this does not require typing any special punctuation symbols or caring about formatand syntax. This process is illustrated in figure 9.
15
x inty intradius float
filled boolean
translate dxint
dyint
x += dxy += dy
class Square
area
return π·radius²
CircleMain
HelloApp
(a) A prompt
x inty intradius float
filled boolean
translate dxint
dyint
x += dxy += dy
area
return π·radius²
Circle SquareMain
HelloApp
(b) The new class
Figure 7: Creating a new class by using a prompt. The context here is the translate method.
16
x inty intradius float
filled boolean
translate dxint
dyint
x += dxy += dy
area
return π·radius²
Circle SquareMain
HelloApp
class TriangleI have no clue what you mean by:class Triangle
Figure 8: An error displayed at the prompt. The context here is HelloApp which does notunderstand the ’class’ command.
app HelloWorld
(a)
HelloWorld
module Main
(b)
class HelloMain
HelloWorld
(c)
Hellomethod main
Main
HelloWorld
(d)
main
print "Hello World"
HelloMain
HelloWorld
(e)
Figure 9: Creating a Hello World application.
17
3.4.2 Visualizing the source code of Envision itself
Envision is currently developed in C++. To get a better idea of how our approach scales to biggerapplications we included a rudimentary C++ parser that was able to import Envision’s sourcecode. Figure 10 shows the result.
Figure 10: Envision visualizing itself. The canvas is zoomed out so that the entire Application isvisible. A raster image was used here, since the inclusion of the vector version would increase thisdocument’s size by 100MB.
In the figure we can see in darker colors the different modules comprising the system. They aregrouped with respect to color and position based on function. Blue modules pertain to visual-ization, gray to the program model, green to input handling, orange to C++ parsing, etc. Herewe can see how Envision adds a new dimension to the Application. It allows the programmerto glance over the entire software piece and explore visually the relation between the differenthigh-level modules.
Zooming in on the ’constructs’ module we can see the different classes that belong to it in Figure11.
Classes here are also arranged in a special way: from left to right and from top to bottom theystart with the top-most construct types such as Application and Module and go to more detailedtypes such as Statement or Loop. Similarly the programmer can arrange the methods within aclass. In all classes in the constructs module the following convention applies: constructors anddestructors appear immediately below the field declarations; core logic methods appear under the
18
EnView QWidget*
QGraphicsScene *scene = new QGraphicsScene(this);HBase::setView(this);scene->setItemIndexMethod(QGraphicsScene::NoIndex);setScene(scene);Parser p;CApplication* a = p.getApp("/home/mitko/workspace/Envision");VApplication* box = new VApplication(NULL, a);scene->addItem(box);box->setPos(-(int) box->boundingRect().width() / 2, -(int) box->boundingRect().height() / 2);setWindowTitle(tr("Envision"));setTransformationAnchor(AnchorUnderMouse);
wheelEvent eventQWheelEvent*
static qreal factor = 1.0;event->delta() > 0
factor *= 0.75;scaleView(0.75);
factor < 4.0
factor *= 1.5;scaleView(1.5);
keyPressEvent eventQKeyEvent*
event->key() == Qt::Key_F12 || event->key() == Qt::Key_F11
QPrinter pr(QPrinter::HighResolution);pr.setOutputFileName("env.pdf");pr.setFullPage(true);QSvgGenerator svggen;svggen.setResolution(90);
event->key() == Qt::Key_F11
pr.setPaperSize(QSize(viewport()->rect().width(), viewport()->rect().height()), QPrinter::Point);QPainter pdfp(&pr);render(&pdfp);svggen.setFileName("view.svg");svggen.setSize(QSize(viewport()->rect().width(), viewport()->rect().height()));QPainter svgPainter(&svggen);render(&svgPainter);svgPainter.end();
pr.setPaperSize(QSize(scene()->sceneRect().width(), scene()->sceneRect().height()), QPrinter::Point);QPainter pdfp(&pr);scene()->render(&pdfp);svggen.setFileName("scene.svg");svggen.setSize(QSize(scene()->sceneRect().width(), scene()->sceneRect().height()));QPainter svgPainter(&svggen);scene()->render(&svgPainter);svgPainter.end();
QGraphicsView::keyPressEvent(event);
scaleView scaleFactorqreal
scale(scaleFactor, scaleFactor);
customEvent eventQEvent *
event->type() == UpdateEvent::EventType
VBase::updateModifiedItems();Construct::deleteErased();
QGraphicsView::customEvent(event);
EnView
ui Ui::EnvisionClass
Envision 0QWidget *parent =
ui.setupUi(this);setCentralWidget(ui.main_view);
~Envision
Envision
main_view EnView*statusbar QStatusBar*
setupUi EnvisionClassQMainWindow*
EnvisionClass->objectName().isEmpty()
EnvisionClass->setObjectName(QString::fromUtf8("EnvisionClass"));
EnvisionClass->resize(600, 600);main_view = new EnView(EnvisionClass);main_view->setObjectName(QString::fromUtf8("main_view"));main_view->setFocusPolicy(Qt::StrongFocus);main_view->setFrameShape(QFrame::NoFrame);main_view->setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing);main_view->setCacheMode(QGraphicsView::CacheBackground);main_view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);main_view->setResizeAnchor(QGraphicsView::AnchorUnderMouse);main_view->setOptimizationFlags(QGraphicsView::DontSavePainterState);EnvisionClass->setCentralWidget(main_view);statusbar = new QStatusBar(EnvisionClass);statusbar->setObjectName(QString::fromUtf8("statusbar"));EnvisionClass->setStatusBar(statusbar);retranslateUi(EnvisionClass);QMetaObject::connectSlotsByName(EnvisionClass);
retranslateUi EnvisionClassQMainWindow*
EnvisionClass->setWindowTitle(QApplication::translate("EnvisionClass", "EnvisionWindow", 0, QApplication::UnicodeUTF8));
Ui_EnvisionClass
EnvisionClass
Envision
new_id static unsigned intid intparent Construct*reps std::list<Representation*>revision interased static std::list<Construct*>
notifyRepresentations
list<Representation*>::iterator it = reps.begin(); it != reps.end(); it++
(*it)->constructChanged();
handleChildChange childConstruct*
int current_revision = revision;onChildChange(child);
revision == current_revision
child->notifyRepresentations();
Construct parentConstruct*
~Construct
clearRepresentations();
contentChanged
++revision;parent
parent->handleChildChange(this); notifyRepresentations();
addRepresentation repRepresentation*
rep
reps.push_back(rep);
removeRepresentation repRepresentation*
reps.remove(rep);
getRepresentations
clearRepresentations
list<Representation*>::iterator it = reps.begin(); it != reps.end(); it++
(*it)->constructRemoved();
reps.clear();
erase
erased.push_back(this);
deleteErased
list<Construct*>::iterator it = erased.begin(); it != erased.end(); ++it
(*it)->clearRepresentations();delete (*it);
erased.clear();
getRevision
return revision;
getParent
return parent;
getId
return id;
onChildChange childConstruct*
Construct
pos int
Cursor pos_int
Cursor
cons Construct*
Representation consConstruct*
cons
cons->addRepresentation(this);
~Representation
cons
cons->removeRepresentation(this);
constructChanged
constructRemoved
cons = NULL;
getConstruct
return cons;
Representation
base
modules CSet<CModule>
CApplication parentConstruct*
getModules
return modules;
getModule nameQString
size_t i = 0; i< modules.size(); ++i
modules[i]->getName().getText() == name
return modules[i];
return NULL;
CApplication
methods CSet<CMethod>fields CSet<CVariableDeclaration>
CClass parentConstruct*
getMethods
return methods;
getMethod nameQString
size_t i = 0; i< methods.size(); ++i
methods[i]->getName().getText() == name
return methods[i];
return NULL;
getFields
return fields;
getField nameQString
size_t i = 0; i< fields.size(); ++i
fields[i]->getName().getText() == name
return fields[i];
return NULL;
CClass
header CTextthen_branch CSequence<CStatement>_branch _branch
CIfElse parentConstruct*
getHeader
return header;
getThen
return then_branch;
getElse
returnelse_branch;
CIfElse
body CSequence<CStatement>header CText
CLoop parentConstruct*
getBody
return body;
getHeader
return header;
CLoop
statements CSequence<CStatement>arguments CSequence<CVariableDeclaration>
CMethod parentConstruct*
getStatements
return statements;
getArguments
return arguments;
CMethod
classes CSet<CClass>
CModule parentConstruct*
setColor(QColor(0x40, 0xA0, 0x40));
getClasses
return classes;
getClass nameQString
size_t i = 0; i < classes.size(); ++i
classes[i]->getName().getText() == name
return classes[i];
return NULL;
CModule
text CTexterror1 CTexterror2 CText
CPrompt parentConstruct*
getText
return text;
getError1
return error1;
getError2
return error2;clearErrors
error1.setText("");error2.setText("");contentChanged();
CPrompt
items std::vector<T*>vec typedef typename std::vector<T*>iterator typedef typename vec::iterator
CSequence parentConstruct*
~CSequence
iterator it = items.begin(); it != items.end(); ++it
*it
delete (*it);
getItems
return items;
size
return items.size();
operator[] iint
return items[i];
insertNewAfter NULLT* after =
C* new_item = new C(this);after == NULL
items.push_back(new_item); iterator it = items.begin(); it != items.end(); ++it
*it == after
items.insert(it + 1, new_item);break;
contentChanged();return new_item;
insertNewBefore NULLT* before =
T* new_item = new T(this);before == NULL
items.insert(items.begin(), new_item); iterator it = items.begin(); it != items.end(); ++it
*it == before
items.insert(it, new_item);break;
contentChanged();return new_item;
remove elemT*
items.erase( find(items.begin(), items.end(), elem));elem->erase();contentChanged();
CSequence
items std::vector<T*>vec typedef typename std::vector<T*>iterator typedef typename vec::iterator
CSet parentConstruct*
~CSet
iterator it = items.begin(); it != items.end(); ++it
*it
delete (*it);
getItems
return items;
size
return items.size();
operator[] iint
return items[i];
insertNew
T* new_item = new T(this);items.push_back(new_item);contentChanged();return new_item;
CSet
text CText
CStatement parentConstruct*
getText
return text;
CStatement
text QString
CText parentConstruct*
getText
return text;setText text
QString
this->text = text;contentChanged();
CText
type CText
CVariableDeclaration parentConstruct*
getType
return type;
CVariableDeclaration
constructs
self Construct*color QColor
Color selfConstruct*
~Color getColor
return color;setColor col
QColor
color = col;self->contentChanged();
Color
self Construct*name CText
Name selfConstruct*
~Name getName
return name;
Name
self Construct*allpos static std::vector<Position*> y int x,auto_placement bool
Position selfConstruct*
allpos.push_back(this);
~Position setPos xint
y int
x = x_;y = y_;auto_placement = false;self->contentChanged();
setAutoPlacement auto_placementbool
bool old = auto_placement;auto_placement = auto_;
old != auto_
self->contentChanged();
getX
return x;
getY
return y;
isAutoPlaced
return auto_placement;
printPosition
CModule* c = dynamic_cast<CModule*> (self);c
qDebug() << "if (module_name == " << c->getName().getText() << " ) m->setPos(" << x << ", " << y << " );";
CClass* cc = dynamic_cast<CClass*> (self);cc
CModule* mod = dynamic_cast<CModule*> (cc->getParent()->getParent());mod && !cc->isAutoPlaced()
qDebug() << "if (module_name == " << mod->getName().getText()<< " && class_name == " << cc->getName().getText() << ") c->setPos(" << x << ", " << y << " );";
CMethod* ccc = dynamic_cast<CMethod*> (self);ccc
CClass* cl = dynamic_cast<CClass*> (ccc->getParent()->getParent());CModule* mod = dynamic_cast<CModule*> (cl->getParent()->getParent());
cl && mod && !ccc->isAutoPlaced()
qDebug() << "if (module_name == " << mod->getName().getText()<< " && class_name == " << cl->getName().getText() << " && method_name == " << ccc->getName().getText()<< ") m->setPos(" << x << ", " << y << " );";
printAll
size_t i = 0; i < allpos.size(); ++i
dynamic_cast<CModule*> (allpos[i])
allpos[i]->printPosition();
size_t i = 0; i < allpos.size(); ++i
dynamic_cast<CClass*> (allpos[i])
allpos[i]->printPosition();
size_t i = 0; i < allpos.size(); ++i
dynamic_cast<CMethod*> (allpos[i])
allpos[i]->printPosition();
Position
visibility Scopeself Construct*
Visibility selfConstruct*
getVisibility setVisibility visibilityScope
this->visibility = visibility;self->contentChanged();
Visibility
helpers
the_instance static HApplication
HApplication
command tokensQStringList
vis VBase*
bool processed = false;tokens.size() > 0
tokens[0] == "module"
CApplication* app = dynamic_cast<CApplication*> (vis->getConstruct());CModule* cmod = app->getModules().insertNew();
tokens.size() > 1
cmod->getName().setText(tokens[1]);
vis->hasPrompt()
cmod->setPos(vis->requestPrompt()->x(), vis->requestPrompt()->y());
VBase::setConsWithPrompt(cmod);processed = true;
return processed;
getInstance
return &the_instance;
keyDigit eventQKeyEvent*
vis VBase*
event->key() == Qt::Key_0
VModule::switchBigNames();
int i = 0; i < vis->scene()->items().size(); ++i
VModule* mod = dynamic_cast<VModule*> (vis->scene()->items()[i]);mod
mod->visualizationChanged();
event->key() == Qt::Key_9
int i = 0; i < vis->scene()->items().size(); ++i
VMethod* vm = dynamic_cast<VMethod*> (vis->scene()->items()[i]);vm
CMethod* cm = dynamic_cast<CMethod*> (vm->getConstruct());cm->getName().getText() == "setStyle"
static bool err = false;err = !err;
err
vm->setStyle(SMethod::getErrorStyle()); (vm->setStyle(SMethod::getNormalStyle()));
vm->visualizationChanged();
event->key() == Qt::Key_8
int i = 0; i < vis->scene()->items().size(); ++i
VMethod* vm = dynamic_cast<VMethod*> (vis->scene()->items()[i]);vm
vm->setStyle(SMethod::getGrayStyle());CMethod* cm = dynamic_cast<CMethod*> (vm->getConstruct());
cm->getName().getText() == "setStyle"
vm->setStyle(SMethod::getHighlightStyle());
cm->getName().getText() == "keyDigit"
vm->setStyle(SMethod::getSourceStyle());
cm->getName().getText() == "updateRepresentation"
vm->setStyle(SMethod::getDestinationStyle());
vm->visualizationChanged();
event->key() == Qt::Key_1
int i = 0; i < vis->scene()->items().size(); ++i
VMethod* vm = dynamic_cast<VMethod*> (vis->scene()->items()[i]);vm
vm->setStyle(SMethod::getNormalStyle());vm->visualizationChanged();
event->key() == Qt::Key_2
static VStackTrace* vst = NULL;vst
vis->scene()->removeItem(vst);delete vst;vst = NULL;
vst = new VStackTrace(NULL);CApplication* app = dynamic_cast<CApplication*> (vis->getConstruct());vst->addMethod(app->getModule("vis")->getClass("VBase")->getMethod("keyPressEvent"), 1525, 0);vst->addVarInfo(app->getModule("vis")->getClass("VBase")->getMethod("keyPressEvent")->getArguments()[0],"Key='2'");vst->addMethod(app->getModule("handlers")->getClass("HBase")->getMethod("keyPressEvent"), 1350, 6);vst->addVarInfo(app->getModule("handlers")->getClass("HBase")->getMethod("keyPressEvent")->getArguments()[0],"Key='2'");vst->addVarInfo(app->getModule("handlers")->getClass("HBase")->getMethod("keyPressEvent")->getArguments()[1],"App name=\"Envision\"");vst->addMethod(app->getModule("handlers")->getClass("HApplication")->getMethod("keyDigit"), 0, 26);vst->addVarInfo(app->getModule("handlers")->getClass("HApplication")->getMethod("keyDigit")->getArguments()[0],"Key='2'");vst->addVarInfo(app->getModule("handlers")->getClass("HApplication")->getMethod("keyDigit")->getArguments()[1],"App name=\"Envision\"");vst->addMethod(app->getModule("vis")->getClass("VStackTrace")->getMethod("addMethod"), 1170, 10);vst->addVarInfo(app->getModule("vis")->getClass("VStackTrace")->getMethod("addMethod")->getArguments()[0],"Name=\"KeyPressEvent\"");vst->addVarInfo(app->getModule("vis")->getClass("VStackTrace")->getMethod("addMethod")->getArguments()[1],"1470");vst->addVarInfo(app->getModule("vis")->getClass("VStackTrace")->getMethod("addMethod")->getArguments()[2], "0");vst->addMethod(app->getModule("vis")->getClass("VLinear")->getMethod("addItem"), 1450, 1);vst->addVarInfo(app->getModule("vis")->getClass("VLinear")->getMethod("addItem")->getArguments()[0],"Item type = VSpacer(10,1680)");vst->addMethod(app->getModule("vis")->getClass("VLinear")->getMethod("updateRepresentation"), 900, 15);vst->setPos(0, 0);vis->scene()->addItem(vst);
HApplication
the_instance static HBasecurrent_view static QGraphicsView*
HBase
tokenize strQString
str = str.simplified();int i = 0;
i < str.size()
false == (str[i].isDigit() || str[i].isLetter() || str[i].isSpace())
str.insert(i + 1, ' ');
i++;
return str.split(' ', QString::SkipEmptyParts);
keyLetter eventQKeyEvent*
vis VBase*
event->ignore();
keyDigit eventQKeyEvent*
vis VBase*
keyLetter(event, vis);
keySymbol eventQKeyEvent*
vis VBase*
keyLetter(event, vis);
keyArrow eventQKeyEvent*
vis VBase*
event->ignore();
keySpace eventQKeyEvent*
vis VBase*
keyLetter(event, vis);
keyTab eventQKeyEvent*
vis VBase*
event->ignore();
keyShift eventQKeyEvent*
vis VBase*
event->ignore();
keyControl eventQKeyEvent*
vis VBase*
event->ignore();
keyAlt eventQKeyEvent*
vis VBase*
event->ignore();
keyDelBackspace eventQKeyEvent*
vis VBase*
event->ignore();
keyEnter eventQKeyEvent*
vis VBase*
event->ignore();
keyOther eventQKeyEvent*
vis VBase*
event->text().size() > 0
keyLetter(event, vis);
buttonRelease eventQGraphicsSceneMouseEvent*
vis VBase*
event->button() == Qt::RightButton
vis->showPrompt(event->pos().x(), event->pos().y()); event->ignore();
mouseMove eventQGraphicsSceneMouseEvent*
vis VBase*
vis
Position* p = dynamic_cast<Position*> (vis->getConstruct());p
p->setPos(vis->x(), vis->y());
event->accept();
event->ignore();
processCommand strQString
vis VBase*
QStringList tokens = tokenize(str);bool processed = false;VBase* elem = vis;
elem && !processed
processed = elem->getHandler()->command(tokens, elem);elem = elem->getParent();
elem == NULL && !processed
HBase* global = HGlobal::getInstance();processed = global->command(tokens, vis);
CPrompt* p = VBase::getPromptCons();processed && p
p->clearErrors();
!processed && p
p->getError1().setText("I have no clue what you mean by:");p->getError2().setText( p->getText().getText() );p->contentChanged();
command tokensQStringList
vis VBase*
return false;
getInstance
return &the_instance;
~HBase setView viewQGraphicsView*
current_view = view;view
return current_view;
mouseMoveEvent eventQGraphicsSceneMouseEvent*
vis VBase*
mouseMove(event, vis);event->isAccepted()
QApplication::postEvent(view(), new UpdateEvent());
mouseReleaseEvent eventQGraphicsSceneMouseEvent*
vis VBase*
buttonRelease(event, vis);event->isAccepted()
QApplication::postEvent(view(), new UpdateEvent());
keyPressEvent eventQKeyEvent*
vis VBase*
switch (event->key()){case Qt::Key_A ... Qt::Key_B:keyLetter(event, vis);break;case Qt::Key_0 ... Qt::Key_9:keyDigit(event, vis);break;case Qt::Key_Underscore:keyLetter(event, vis);break;case Qt::Key_Exclam ... Qt::Key_Slash:keySymbol(event, vis);break;case Qt::Key_Colon ... Qt::Key_At:keySymbol(event, vis);break;case Qt::Key_BracketLeft ... Qt::Key_AsciiCircum:keySymbol(event, vis);break;case Qt::Key_QuoteLeft ... Qt::Key_AsciiTilde:keySymbol(event, vis);break;case Qt::Key_Return:keyEnter(event, vis);break;case Qt::Key_Enter:keyEnter(event, vis);break;case Qt::Key_Space:keySpace(event, vis);break;case Qt::Key_Backspace:keyDelBackspace(event, vis);break;case Qt::Key_Delete:keyDelBackspace(event, vis);break;case Qt::Key_Tab ... Qt::Key_Backtab:keyTab(event, vis);break;case Qt::Key_Shift:keyShift(event, vis);break;case Qt::Key_Control:keyControl(event, vis);break;case Qt::Key_Alt:keyAlt(event, vis);break;case Qt::Key_Left:keyArrow(event, vis);break;case Qt::Key_Up:keyArrow(event, vis);break;case Qt::Key_Right:keyArrow(event, vis);break;case Qt::Key_Down:keyArrow(event, vis);break;default:keyOther(event, vis);}
event->isAccepted()
QApplication::postEvent(view(), new UpdateEvent());
HBase
the_instance static HClass
HClass
command tokensQStringList
vis VBase*
bool processed = false;tokens.size() > 0
tokens[0] == "method"
CClass* cc = dynamic_cast<CClass*> (vis->getConstruct());CMethod* m = cc->getMethods().insertNew();CStatement* s = m->getStatements().insertNewAfter<CStatement> (NULL);int next = 1;
tokens.size() > next
tokens[next] == "private"
m->setVisibility(Visibility::PRIVATE);++next;
tokens[next] == "protected"
m->setVisibility(Visibility::PROTECTED);++next;
tokens[next] == "public"
m->setVisibility(Visibility::PUBLIC);++next;
tokens.size() > next
m->getName().setText(tokens[next]);++next;
CVariableDeclaration* arg = NULL;
; next < tokens.size(); ++next
tokens[next] == ","
arg = NULL;continue;
arg == NULL
arg = m->getArguments().insertNewAfter<CVariableDeclaration> ();arg->getName().setText(tokens[next]);
arg->getType().getText().size() > 0
arg->getType().setText(arg->getType().getText() + " ");
arg->getType().setText(arg->getType().getText() + tokens[next]);
vis->removePrompt();vis->getCursor().pos = 0;VBase::focus(&s->getText());processed = true;
tokens[0] == "field"
CClass* cc = dynamic_cast<CClass*> (vis->getConstruct());CVariableDeclaration* vd = cc->getFields().insertNew();int next = 1;
tokens.size() > next
tokens[next] == "private"
vd->setVisibility(Visibility::PRIVATE);++next;
tokens[next] == "protected"
vd->setVisibility(Visibility::PROTECTED);++next;
tokens[next] == "public"
vd->setVisibility(Visibility::PUBLIC);++next;
tokens.size() > next
vd->getName().setText(tokens[next]);++next;
; next < tokens.size(); ++next
vd->getType().setText(vd->getType().getText() + tokens[next]);tokens.size() - 1 > next
vd->getType().setText(vd->getType().getText() + " ");
vis->removePrompt();vis->getCursor().pos = 0;VBase::focus(&vd->getName());processed = true;
return processed;
getInstance
return &the_instance;
HClass
the_instance static HClassField
HClassField
keyEnter eventQKeyEvent*
vis VBase*
CVariableDeclaration* vd = dynamic_cast<CVariableDeclaration*> (vis->getConstruct());CSet<CVariableDeclaration>* set = dynamic_cast<CSet<CVariableDeclaration>*> (vd->getParent());vis->scene()->clearFocus();CVariableDeclaration* new_var = set->insertNew();new_var->setVisibility( vd->getVisibility() );VBase::focus(&new_var->getName());vis->getCursor().pos = 0;
keyControl eventQKeyEvent*
vis VBase*
VClassField* cf = dynamic_cast<VClassField*> (vis);cf->getCursor().pos = 0;
! cf->getName().HasFocusInHierarchy()
cf->getName().setFocus(); cf->getType().setFocus();
getInstance
return &the_instance;
HClassField
the_instance static HGlobal
HGlobal
command tokensQStringList
vis VBase*
bool processed = false;tokens.size() > 0
tokens[0] == "app" || tokens[0] == "application"
CApplication* app = new CApplication(NULL);tokens.size() > 1
app->getName().setText( tokens[1] );
VApplication* vapp = new VApplication(NULL, app);vis->scene()->addItem(vapp);vapp->setPos(-vapp->boundingRect().width()/2, -vapp->boundingRect().height()/2);CPrompt* p = dynamic_cast<CPrompt*> ( vis->getConstruct() );delete vis;delete p;vapp->showPrompt();processed = true;
tokens[0] == "save"
Position::printAll();
return processed;
getInstance
return &the_instance;
HGlobal
the_instance static HIfElse
HIfElse
keyControl eventQKeyEvent*
vis VBase*
VIfElse* v = dynamic_cast<VIfElse*> (vis);v->switchFocus();event->accept();
getInstance
return &the_instance;
HIfElse
the_instance static HMethodArgument
HMethodArgument
keyEnter eventQKeyEvent*
vis VBase*
CVariableDeclaration* vd = dynamic_cast<CVariableDeclaration*> (vis->getConstruct());CSequence<CVariableDeclaration>* seq = dynamic_cast<CSequence<CVariableDeclaration>*> (vd->getParent());vis->scene()->clearFocus();CVariableDeclaration* new_var = seq->insertNewAfter<CVariableDeclaration> (vd);VBase::focus(&new_var->getName());vis->getCursor().pos = 0;
keyControl eventQKeyEvent*
vis VBase*
VMethodArgument* ma = dynamic_cast<VMethodArgument*> (vis);ma->getCursor().pos = 0;
! ma->getName().HasFocusInHierarchy()
ma->getName().setFocus(); ma->getType().setFocus();
getInstance
return &the_instance;
HMethodArgument
the_instance static HModule
HModule
command tokensQStringList
vis VBase*
bool processed = false;tokens.size() > 0
tokens[0] == "class"
CModule* mod = dynamic_cast<CModule*> (vis->getConstruct());CClass* cc = mod->getClasses().insertNew();
tokens.size() > 1
cc->getName().setText(tokens[1]);
vis->hasPrompt()
cc->setPos(vis->requestPrompt()->x(), vis->requestPrompt()->y());
VBase::setConsWithPrompt(cc);processed = true;
return processed;
getInstance
return &the_instance;
HModule
the_instance static HPrompt
HPrompt
keyEnter eventQKeyEvent*
vis VBase*
CPrompt* p = dynamic_cast<CPrompt*> (vis->getConstruct());processCommand(p->getText().getText(), vis);event->accept();
buttonRelease eventQGraphicsSceneMouseEvent*
vis VBase*
event->accept();
getInstance
return &the_instance;
HPrompt
the_instance static HSequence
HSequence
keyArrow eventQKeyEvent*
vis VBase*
VSequence<CStatement, VStatement>* st = dynamic_cast<VSequence<CStatement, VStatement>*> (vis);st
event->key() == Qt::Key_Up
(*st->getItems().begin())->HasFocusInHierarchy()
event->ignore();return;
int i = st->size() -1; i > 0; --i
st->getItems()[i]->HasFocusInHierarchy()
st->getItems()[i - 1]->setFocus();st->getItems()[i - 1]->visualizationChanged();return;
event->key() == Qt::Key_Down
(*st->getItems().rbegin())->HasFocusInHierarchy()
event->ignore();return;
int i = 0; i < st->size(); ++i
st->getItems()[i]->HasFocusInHierarchy()
st->getItems()[i + 1]->setFocus();st->getItems()[i + 1]->visualizationChanged();return;
getInstance
return &the_instance;
HSequence
the_instance static HStatement
HStatement
keyEnter eventQKeyEvent*
vis VBase*
VStatement* vs = dynamic_cast<VStatement*> (vis);CStatement* st = dynamic_cast<CStatement*> (vs->getConstruct());CSequence<CStatement>* cs = dynamic_cast<CSequence<CStatement>*> (st->getParent());vis->scene()->clearFocus();
st->getText().getText().startsWith("if ")
CIfElse* ifelse = cs->insertNewAfter<CIfElse> (st);ifelse->getHeader().setText(st->getText().getText().mid(3));CStatement* ns = ifelse->getThen().insertNewAfter<CStatement> ();VBase::focus(&ns->getText());cs->remove(st);
st->getText().getText().startsWith("for ") || st->getText().getText().startsWith("while ")
CLoop* loop = cs->insertNewAfter<CLoop> (st);QString rest = st->getText().getText().mid(st->getText().getText().indexOf(' ') + 1);
st->getText().getText().startsWith("for ") && st->getText().getText().simplified().split(' ').count() == 2
loop->getHeader().setText("int i = 0; i<" + rest + "; ++i"); loop->getHeader().setText(rest);
CStatement* ns = loop->getBody().insertNewAfter<CStatement> ();VBase::focus(&ns->getText());cs->remove(st);
CStatement* ns = cs->insertNewAfter<CStatement> (st);VBase::focus(&ns->getText());
vis->getCursor().pos = 0;
getInstance
return &the_instance;
HStatement
the_instance static HText
adjustCursor visVBase*
vis->getCursor().pos < 0
vis->getCursor().pos = 0;
CText* text = dynamic_cast<CText*> (vis->getConstruct());vis->getCursor().pos > text->getText().length()
vis->getCursor().pos = text->getText().length();
vis->visualizationChanged();
HText
keyLetter eventQKeyEvent*
vis VBase*
vis->getCursor().pos++;CText* text = dynamic_cast<CText*> (vis->getConstruct());text->setText(text->getText().insert(vis->getCursor().pos - 1, event->text()));adjustCursor(vis);
keyArrow eventQKeyEvent*
vis VBase*
switch (event->key()){case Qt::Key_Left:vis->getCursor().pos--;break;case Qt::Key_Right:vis->getCursor().pos++;break;default:{event->ignore();return;}}adjustCursor(vis);
keyDelBackspace eventQKeyEvent*
vis VBase*
Cursor& cursor = vis->getCursor();CText* text = dynamic_cast<CText*> (vis->getConstruct());switch (event->key()){case Qt::Key_Backspace:{cursor.pos--;
cursor.pos >= 0
text->setText(text->getText().remove(cursor.pos, 1)); cursor.pos = 0;
}break;case Qt::Key_Delete:{
cursor.pos < text->getText().length()
text->setText(text->getText().remove(cursor.pos, 1));
}break;}adjustCursor(vis);
buttonRelease eventQGraphicsSceneMouseEvent*
vis VBase*
CText* text = dynamic_cast<CText*> (vis->getConstruct());int pos = event->pos().x();
vis->boundingRect().width() == 0 || text->getText().length() == 0
vis->getCursor().pos = 0; vis->getCursor().pos = pos / (vis->boundingRect().width() / text->getText().length());
adjustCursor(vis);
getInstance
return &the_instance;
HText
= QEvent::TypeUpdateEvent
UpdateEvent
handlers
app CApplication*
parseDir pathQString
QDir dir(path);dir.dirName() == "debug" || dir.dirName() == "release"
return;
dir.setFilter(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);createModule(dir.dirName());QStringList filters;filters << "*.h";dir.setNameFilters(filters);QFileInfoList list = dir.entryInfoList();
int i = 0; i < list.size(); ++i
QFileInfo file = list.at(i);parseFile(file.absoluteFilePath(), dir.dirName());
filters.clear();filters << "*.cpp";dir.setNameFilters(filters);list = dir.entryInfoList();
int i = 0; i < list.size(); ++i
QFileInfo file = list.at(i);parseFile(file.absoluteFilePath(), dir.dirName());
dir.setFilter(QDir::AllDirs | QDir::NoSymLinks | QDir::NoDotAndDotDot);list = dir.entryInfoList();
int i = 0; i < list.size(); ++i
QFileInfo file = list.at(i);parseDir(file.absoluteFilePath());
parseFile pathQString
module QString
qDebug() << "IN parseFile " << path;QFile f(path);
!f.open(QIODevice::ReadOnly | QIODevice::Text)
return;
QTextStream text(&f);QStringList lines = removeComments(text);qDebug() << "===================================";
int i = 0; i < lines.size(); ++i
qDebug() << "* " << lines[i];lines[i].size() > 300
qDebug() << " Line too long";abort();
lines = putOnNewLine(lines, "{");lines = putOnNewLine(lines, "}");lines = putOnNewLine(lines, "if");lines = putOnNewLine(lines, "else");lines = putOnNewLine(lines, "for");lines = putOnNewLine(lines, "while");lines = normalizeParenthesis(lines);
int i = 0; i < lines.size(); ++i
lines[i] = lines[i].simplified();
int i = lines.size() - 1; i >= 0; --i
lines[i].isEmpty()
lines.removeAt(i);
qDebug() << "===================================";
int i = 0; i < lines.size(); ++i
qDebug() << "* " << lines[i];lines[i].size() > 300
qDebug() << " Line too long";abort();
parseFileEntry(module, lines);qDebug() << "OUT parseFile " << path;
removeComments textQTextStream&
QStringList res;QString all = text.readAll();bool in_comment = false;bool in_string = false;QChar match;res.append("");
int i = 0; i < all.size(); ++i
in_comment
all[i] == match
match == '\n'
in_comment = false;res.last().size() > 0
res.append("");
match == '*' && all[i + 1] == '/'
match = '/'; match == '/'
in_comment = false;
in_string
res.last().append(all[i]);all[i] == match && all[i - 1] != SLASH
in_string = false;
all[i] == '\n'
res.append(""); all[i] == '/' && all[i + 1] == '/'
in_comment = true;match = '\n';
all[i] == '/' && all[i + 1] == '*'
in_comment = true;match = '*';
all[i] == '\''
in_string = true;match = '\'';res.last().append(all[i]);
all[i] == '"'
in_string = true;match = '"';res.last().append(all[i]);
res.last().append(all[i]);
return res;
putOnNewLine linesQStringList&
separator QString
QStringList res;res.append("");
int i = 0; i < lines.length(); ++i
qDebug() << " separating line : " << lines[i];QStringList parts = lines[i].simplified().split(separator);
!res.last().isEmpty()
res.append("");
bool in_string = false;QChar match;QChar val;
int k = 0; k < parts.size(); ++k
int c = 0; c < parts[k].size(); ++c
val = parts[k][c];res.last().append(val);
in_string && val == match && (c == 0 || parts[k][c - 1] != SLASH)
in_string = false; !in_string && (val == '\'' || val == '"')
in_string = true;match = val;
k + 1 < parts.size()
bool allow_new_line = !in_string;separator[0].isLetter()
!parts[k].isEmpty() && val.isLetterOrNumber()
allow_new_line = false;
!parts[k + 1].isEmpty() && parts[k + 1][0].isLetterOrNumber()
allow_new_line = false;
allow_new_line && !res.last().isEmpty()
res.append("");
res.last().append(separator);allow_new_line
res.append("");
res.last().isEmpty()
res.removeLast();
qDebug() << "Finished pre-processing separators";return res;
normalizeParenthesis linesQStringList&
QStringList res;res.append("");int level = 0;bool in_string = false;QChar match;QChar val;QString line;
int i = 0; i < lines.length(); ++i
line = lines[i];res.last().append(line);
int k = 0; k < line.size(); ++k
val = line[k];in_string && val == match && line[k - 1] != SLASH
in_string = false; !in_string && (val == '\'' || val == '"')
in_string = true;match = val;
!in_string && val == '('
++level; !in_string && val == ')'
--level;
level == 0 && !res.last().isEmpty()
res.append("");
return res;
getLoopIfElseHeader lineQString
header QString&
rest QString&
!line.startsWith('(')
qDebug() << "Extracting incorrect header: " << line;CMethod* m = (CMethod*) NULL;qDebug() << m->getName().getText();
bool in_string = false;QChar match;QChar val;int level = 1;header = "";rest = "";
int i = 1; i < line.size(); ++i
val = line[i];in_string && val == match && line[i - 1] != SLASH
in_string = false; !in_string && (val == '\'' || val == '"')
in_string = true;match = val;
!in_string && val == '('
++level; !in_string && val == ')'
--level;
level > 0
header.append(val); rest = line.right(line.length() - i - 1).simplified();break;
header = header.simplified();
parseFileEntry moduleQString
lines QStringList&
qDebug() << "IN parseFileEntry -------------" << lines.first();
lines.isEmpty() == false
qDebug() << "file entry next line " << lines.first();
(lines.first().startsWith("class") || lines.first().contains("::")) == false|| lines.first().split("::").size() > 2
lines.removeFirst();lines.isEmpty()
break;
lines.isEmpty()
break;
qDebug() << "file entry next interesting line: " << lines.first();lines.first().startsWith("class") && !lines.first().contains(';')
QString class_name = lines.first().split(' ')[1].split(':').first();createClass(module, class_name);
lines.first() != "{"
lines.removeFirst();
parseClassDeclaration(module, class_name, lines);
lines.first().contains("::") && lines.first().contains('(') && !lines.first().contains('=')
qDebug() << " recognized a method definition ";QStringList s = lines.first().split("::");s[0] = s[0].simplified();s[1] = s[1].simplified();QString class_name = s[0].split(' ').last().simplified();QString method_name = s[1].split('(').first().simplified();CClass* cl = app->getModule(module)->getClass(class_name);
cl
CMethod* m = cl->getMethod(method_name);
lines.first() != "{"
lines.removeFirst();
parseBody(m->getStatements(), lines);
qDebug() << "No such class " << class_name;CMethod* m = (CMethod*) NULL;qDebug() << m->getName().getText();
lines.removeFirst();
qDebug() << "OUT parseFileEntry ";
parseClassDeclaration moduleQString
class_name QString
lines QStringList&
qDebug() << "IN parseClassDeclaration " << lines.first();lines.first() != "{"
qDebug() << "Parsing a class that does not begin with {";
lines.removeFirst();int level = 1;bool isprivate = true;bool isprotected = false;bool ispublic = false;
level > 0
lines.first() == "{"
level++;lines.removeFirst();continue;
lines.first() == "}"
level--;lines.removeFirst();continue;
lines.first().contains('(')
QString method_name = lines.first().left(lines.first().indexOf('(')).simplified().split(' ').last();qDebug() << "class creating method " << method_name << " " << lines.first();CMethod* m = createMethod(module, class_name, method_name);
isprivate
m->setVisibility(Visibility::PRIVATE);
isprotected
m->setVisibility(Visibility::PROTECTED);
ispublic
m->setVisibility(Visibility::PUBLIC);
parseMethodArguments(module, class_name, method_name, lines);
lines.first().contains(';') == false && lines.first().contains("{") == false
lines.removeFirst();
lines.first().contains('{')
parseBody(app->getModule(module)->getClass(class_name)->getMethod(method_name)->getStatements(), lines); lines.removeFirst();
qDebug() << "MID parseClassDeclaration " << lines.first() << " level " << level;
lines.first().simplified() == "public:"
ispublic = true;isprivate = false;isprotected = false;lines.removeFirst();
lines.first().simplified() == "private:"
ispublic = false;isprivate = true;isprotected = false;lines.removeFirst();
lines.first().simplified() == "protected:"
ispublic = false;isprivate = false;isprotected = true;lines.removeFirst();
lines.first().endsWith(';') && !lines.first().contains('{')
QString decl = lines.first();decl.chop(1);decl = decl.simplified();QString var = decl.split(' ').last();QString type = decl.left(decl.length() - var.length() - 1);
var.startsWith('*')
var = var.right(var.length() - 1);type.append('*');
qDebug() << "var " << var << " type" << type;CVariableDeclaration* v = app->getModule(module)->getClass(class_name)->getFields().insertNew();v->getName().setText(var);v->getType().setText(type);
isprivate
v->setVisibility(Visibility::PRIVATE);
isprotected
v->setVisibility(Visibility::PROTECTED);
ispublic
v->setVisibility(Visibility::PUBLIC);
lines.removeFirst();
lines.removeFirst();
qDebug() << "OUT parseClassDeclaration ";
parseMethodArguments moduleQString
class_name QString
method_name QString
lines QStringList&
qDebug() << "IN parseMethodArguments " << lines.first();QString line = lines.first();
!line.contains(')')
lines.removeFirst();line += lines.first();
QStringList pairs = line.split('(')[1].split(')')[0].simplified().split(',');pairs.size() == 0
return;
pairs.size() == 1 && pairs[0].size() < 1
return;
int i = 0; i < pairs.size(); ++i
QString var = pairs[i].split(' ').last();QString type;
var.length() == pairs[i].length()
var = "";type = pairs[i];
type = pairs[i].left(pairs[i].length() - var.length() - 1);
var.startsWith('*')
var = var.right(var.length() - 1);type.append('*');
qDebug() << "var " << var << " type" << type;CVariableDeclaration* v =app->getModule(module)->getClass(class_name)->getMethod(method_name)->getArguments().insertNewAfter<CVariableDeclaration> ();v->getName().setText(var);v->getType().setText(type);
qDebug() << "OUT parseMethodArguments " << lines.first();
parseBody sCSequence<CStatement>&
lines QStringList&
qDebug() << "IN parseBody " << lines.first();lines.first() != "{"
lines.first() == "for" || lines.first() == "while"
parseLoop(s, lines); lines.first() == "if"
parseIfElse(s, lines); !lines.first().contains(';')
qDebug() << "IN parseBody single add " << lines.first();s.insertNewAfter<CStatement> ()->getText().setText(lines.first());lines.removeFirst();
qDebug() << "IN parseBody single add " << lines.first();s.insertNewAfter<CStatement> ()->getText().setText(lines.first());lines.removeFirst();
lines.removeFirst();int level = 1;
level > 0
qDebug() << "IN parseBody block current line " << lines.first();lines.first() == "}"
level--;
lines.first() == "{"
level++;
lines.first() == "for" || lines.first() == "while"
parseLoop(s, lines); lines.first() == "if"
parseIfElse(s, lines); level > 0
qDebug() << "IN parseBody block add " << lines.first();s.insertNewAfter<CStatement> ()->getText().setText(lines.first());lines.removeFirst();
lines.first() != "}"
qDebug() << "Illegal exit from body ";CMethod* m = (CMethod*) NULL;qDebug() << m->getName().getText();
lines.removeFirst();
qDebug() << "OUT parseBody ";
parseLoop sCSequence<CStatement>&
lines QStringList&
qDebug() << "IN parseLoop " << lines.first();lines.removeFirst();QString header;QString rest;getLoopIfElseHeader(lines.first(), header, rest);CLoop* loop = s.insertNewAfter<CLoop> ();loop->getHeader().setText(header);lines[0] = rest;
lines.first().length() < 1
lines.removeFirst();
parseBody(loop->getBody(), lines);qDebug() << "OUT parseLoop " << lines.first();
parseIfElse sCSequence<CStatement>&
lines QStringList&
qDebug() << "IN parseIfElse " << lines.first();lines.removeFirst();QString header;QString rest;getLoopIfElseHeader(lines.first(), header, rest);CIfElse* ife = s.insertNewAfter<CIfElse> ();ife->getHeader().setText(header);lines[0] = rest;
lines.first().length() < 1
lines.removeFirst();
parseBody(ife->getThen(), lines);lines.first() == "else"
lines.removeFirst();parseBody(ife->getElse(), lines);
qDebug() << "OUT parseIfElse " << lines.first();
createModule module_nameQString
CModule* m = app->getModules().insertNew();m->getName().setText(module_name);
module_name == "Envision"
m->setPos( 17000 , 20500 );
module_name == "base"
m->setPos( 0 , 0 );
module_name == "constructs"
m->setPos( 11500 , 0 );
module_name == "helpers"
m->setPos( 16000 , 0 );
module_name == "handlers"
m->setPos( 12500 , 7500 );
module_name == "parsers"
m->setPos( 24000 , 0 );
module_name == "styles"
m->setPos( 0 , 18000 );
module_name == "vis"
m->setPos( 0 , 5000 );
module_name == "vis_helpers"
m->setPos( 6000 , 18000 );
module_name == "Envision"
m->setColor(QColor(0xA0, 0x40, 0xA0));
module_name == "base"
m->setColor(QColor(0xFF, 0xFF, 0x00));
;module_name == "constructs"
m->setColor(QColor(0x80, 0x80, 0x80));
module_name == "helpers"
m->setColor(QColor(0x80, 0x80, 0x80));
module_name == "handlers"
m->setColor(QColor(0x40, 0xA0, 0x40));
module_name == "parsers"
m->setColor(QColor(0xFF, 0x66, 0x00));
module_name == "styles"
m->setColor(QColor(0x40, 0x40, 0xA0));
module_name == "vis"
m->setColor(QColor(0x40, 0x40, 0xA0));
module_name == "vis_helpers"
m->setColor(QColor(0x40, 0x40, 0xA0));
return m;
createClass module_nameQString
class_name QString
CClass* c = app->getModule(module_name)->getClasses().insertNew();c->getName().setText(class_name);
module_name == "Envision" && class_name == "EnView"
c->setPos( 1300 , 0 );
module_name == "Envision" && class_name == "Envision"
c->setPos( 0 , 0 );
module_name == "Envision" && class_name == "Ui_EnvisionClass"
c->setPos( 0 , 400 );
module_name == "Envision" && class_name == "EnvisionClass"
c->setPos( 1300 , 1000 );
module_name == "base" && class_name == "Construct"
c->setPos( 0 , 0 );
module_name == "base" && class_name == "Cursor"
c->setPos( 1600 , 1800 );
module_name == "base" && class_name == "Representation"
c->setPos( 0 , 1800 );
module_name == "constructs" && class_name == "CApplication"
c->setPos( 0 , 0 );
module_name == "constructs" && class_name == "CClass"
c->setPos( 0 , 1000 );
module_name == "constructs" && class_name == "CIfElse"
c->setPos( 1300 , 700 );
module_name == "constructs" && class_name == "CLoop"
c->setPos( 1300 , 300 );
module_name == "constructs" && class_name == "CMethod"
c->setPos( 0 , 1900 );
module_name == "constructs" && class_name == "CModule"
c->setPos( 0 , 500 );
module_name == "constructs" && class_name == "CPrompt"
c->setPos( 3100 , 2200 );
module_name == "constructs" && class_name == "CSequence"
c->setPos( 2400 , 0 );
module_name == "constructs" && class_name == "CSet"
c->setPos( 2400 , 1500 );
module_name == "constructs" && class_name == "CStatement"
c->setPos( 1300 , 0 );
module_name == "constructs" && class_name == "CText"
c->setPos( 1300 , 1600 );
module_name == "constructs" && class_name == "CVariableDeclaration"
c->setPos( 1300 , 1300 );
module_name == "helpers" && class_name == "Color"
c->setPos( 0 , 300 );
module_name == "helpers" && class_name == "Name"
c->setPos( 0 , 0 );
module_name == "helpers" && class_name == "Position"
c->setPos( 0 , 900 );
module_name == "helpers" && class_name == "Visibility"
c->setPos( 0 , 600 );
module_name == "handlers" && class_name == "HApplication"
c->setPos( 3600 , 900 );
module_name == "handlers" && class_name == "HBase"
c->setPos( 0 , 0 );
module_name == "handlers" && class_name == "HClass"
c->setPos( 3600 , 3900 );
module_name == "handlers" && class_name == "HClassField"
c->setPos( 7300 , 0 );
module_name == "handlers" && class_name == "HGlobal"
c->setPos( 3600 , 0 );
module_name == "handlers" && class_name == "HIfElse"
c->setPos( 7300 , 3500 );
module_name == "handlers" && class_name == "HMethodArgument"
c->setPos( 7300 , 800 );
module_name == "handlers" && class_name == "HModule"
c->setPos( 3600 , 3200 );
module_name == "handlers" && class_name == "HPrompt"
c->setPos( 0 , 4400 );
module_name == "handlers" && class_name == "HSequence"
c->setPos( 7300 , 1700 );
module_name == "handlers" && class_name == "HStatement"
c->setPos( 7300 , 2700 );
module_name == "handlers" && class_name == "HText"
c->setPos( 0 , 2600 );
module_name == "handlers" && class_name == "UpdateEvent"
c->setPos( 8600 , 5000 );
module_name == "parsers" && class_name == "Parser"
c->setPos( 0 , 0 );
module_name == "styles" && class_name == "SApplication"
c->setPos( 600 , 0 );
module_name == "styles" && class_name == "SBox"
c->setPos( 0 , 0 );
module_name == "styles" && class_name == "SClass"
c->setPos( 1900 , 0 );
module_name == "styles" && class_name == "SClassName"
c->setPos( 900 , 2900 );
module_name == "styles" && class_name == "SIfElse"
c->setPos( 4200 , 0 );
module_name == "styles" && class_name == "SInvisible"
c->setPos( 5200 , 2300 );
module_name == "styles" && class_name == "SLoop"
c->setPos( 5000 , 0 );
module_name == "styles" && class_name == "SMethod"
c->setPos( 2600 , 0 );
module_name == "styles" && class_name == "SMethodName"
c->setPos( 1300 , 2900 );
module_name == "styles" && class_name == "SModule"
c->setPos( 1200 , 0 );
module_name == "styles" && class_name == "SModuleName"
c->setPos( 500 , 2900 );
module_name == "styles" && class_name == "SPrompt"
c->setPos( 4400 , 2300 );
module_name == "styles" && class_name == "SStackTrace"
c->setPos( 4400 , 2900 );
module_name == "styles" && class_name == "SText"
c->setPos( 0 , 2900 );
module_name == "styles" && class_name == "SType"
c->setPos( 1700 , 2900 );
module_name == "styles" && class_name == "SVarInfo"
c->setPos( 2100 , 2900 );
module_name == "vis" && class_name == "ClassIcon"
c->setPos( 6500 , 1300 );
module_name == "vis" && class_name == "IfElseIcon"
c->setPos( 7700 , 7000 );
module_name == "vis" && class_name == "LoopIcon"
c->setPos( 7500 , 5500 );
module_name == "vis" && class_name == "MethodIcon"
c->setPos( 8000 , 4200 );
module_name == "vis" && class_name == "VApplication"
c->setPos( 6000 , 0 );
module_name == "vis" && class_name == "VBase"
c->setPos( 0 , 0 );
module_name == "vis" && class_name == "VBox"
c->setPos( 0 , 3400 );
module_name == "vis" && class_name == "VBoxed"
c->setPos( 700 , 10900 );
module_name == "vis" && class_name == "VClass"
c->setPos( 6000 , 1300 );
module_name == "vis" && class_name == "VClassField"
c->setPos( 7800 , 2300 );
module_name == "vis" && class_name == "VDummy"
c->setPos( 7800 , 9000 );
module_name == "vis" && class_name == "VFields"
c->setPos( 6000 , 2300 );
module_name == "vis" && class_name == "VGrid"
c->setPos( 0 , 6600 );
module_name == "vis" && class_name == "VIfElse"
c->setPos( 6000 , 7000 );
module_name == "vis" && class_name == "VLinear"
c->setPos( 3300 , 8600 );
module_name == "vis" && class_name == "VLoop"
c->setPos( 6000 , 5500 );
module_name == "vis" && class_name == "VMethod"
c->setPos( 6000 , 4200 );
module_name == "vis" && class_name == "VMethodArgument"
c->setPos( 6900 , 4200 );
module_name == "vis" && class_name == "VModule"
c->setPos( 6000 , 400 );
module_name == "vis" && class_name == "VPrompt"
c->setPos( 7300 , 9000 );
module_name == "vis" && class_name == "VRuntimeVariableInfo"
c->setPos( 7400 , 10800 );
module_name == "vis" && class_name == "VSequence"
c->setPos( 1400 , 8600 );
module_name == "vis" && class_name == "VSet"
c->setPos( 0 , 8600 );
module_name == "vis" && class_name == "VSpacer"
c->setPos( 0 , 10900 );
module_name == "vis" && class_name == "VStackTrace"
c->setPos( 6000 , 10800 );
module_name == "vis" && class_name == "VStatement"
c->setPos( 6000 , 5100 );
module_name == "vis" && class_name == "VText"
c->setPos( 6000 , 9000 );
module_name == "vis_helpers" && class_name == "VisFactory"
c->setPos( 0 , 100 );
return c;
createMethod module_nameQString
class_name QString
method_name QString
CMethod* m = app->getModule(module_name)->getClass(class_name)->getMethods().insertNew();m->getName().setText(method_name);
module_name == "Envision" && class_name == "EnView" && method_name == "EnView"
m->setPos( 12 , 3 );
module_name == "Envision" && class_name == "EnView" && method_name == "wheelEvent"
m->setPos( 0 , 450 );
module_name == "Envision" && class_name == "EnView" && method_name == "scaleView"
m->setPos( 0 , 750 );
module_name == "Envision" && class_name == "EnView" && method_name == "customEvent"
m->setPos( 800 , 0 );
module_name == "Envision" && class_name == "Envision" && method_name == "~Envision"
m->setPos( 400 , 0 );
module_name == "Envision" && class_name == "Ui_EnvisionClass" && method_name == "setupUi"
m->setPos( 0 , 0 );
module_name == "Envision" && class_name == "Ui_EnvisionClass" && method_name == "retranslateUi"
m->setPos( 0 , 650 );
module_name == "base" && class_name == "Construct" && method_name == "notifyRepresentations"
m->setPos( 0 , 450 );
module_name == "base" && class_name == "Construct" && method_name == "handleChildChange"
m->setPos( 0 , 900 );
module_name == "base" && class_name == "Construct" && method_name == "Construct"
m->setPos( 0 , 50 );
module_name == "base" && class_name == "Construct" && method_name == "~Construct"
m->setPos( 350 , 50 );
module_name == "base" && class_name == "Construct" && method_name == "contentChanged"
m->setPos( 950 , 1050 );
module_name == "base" && class_name == "Construct" && method_name == "addRepresentation"
m->setPos( 0 , 300 );
module_name == "base" && class_name == "Construct" && method_name == "removeRepresentation"
m->setPos( 450 , 300 );
module_name == "base" && class_name == "Construct" && method_name == "getRepresentations"
m->setPos( 1150 , 300 );
module_name == "base" && class_name == "Construct" && method_name == "clearRepresentations"
m->setPos( 0 , 600 );
module_name == "base" && class_name == "Construct" && method_name == "erase"
m->setPos( 0 , 1100 );
module_name == "base" && class_name == "Construct" && method_name == "deleteErased"
m->setPos( 0 , 1200 );
module_name == "base" && class_name == "Construct" && method_name == "getRevision"
m->setPos( 1150 , 200 );
module_name == "base" && class_name == "Construct" && method_name == "getParent"
m->setPos( 1150 , 100 );
module_name == "base" && class_name == "Construct" && method_name == "getId"
m->setPos( 1150 , 0 );
module_name == "base" && class_name == "Construct" && method_name == "onChildChange"
m->setPos( 950 , 950 );
module_name == "base" && class_name == "Cursor" && method_name == "Cursor"
m->setPos( 0 , 0 );
module_name == "base" && class_name == "Representation" && method_name == "Representation"
m->setPos( 0 , 0 );
module_name == "base" && class_name == "Representation" && method_name == "~Representation"
m->setPos( 400 , 0 );
module_name == "base" && class_name == "Representation" && method_name == "constructChanged"
m->setPos( 950 , 250 );
module_name == "base" && class_name == "Representation" && method_name == "getConstruct"
m->setPos( 950 , 0 );
module_name == "constructs" && class_name == "CApplication" && method_name == "CApplication"
m->setPos( 0 , 0 );
module_name == "constructs" && class_name == "CApplication" && method_name == "getModules"
m->setPos( 450 , 0 );
module_name == "constructs" && class_name == "CApplication" && method_name == "getModule"
m->setPos( 450 , 100 );
module_name == "constructs" && class_name == "CClass" && method_name == "CClass"
m->setPos( 0 , 0 );
module_name == "constructs" && class_name == "CClass" && method_name == "getMethods"
m->setPos( 450 , 0 );
module_name == "constructs" && class_name == "CClass" && method_name == "getMethod"
m->setPos( 450 , 200 );
module_name == "constructs" && class_name == "CClass" && method_name == "getFields"
m->setPos( 450 , 100 );
module_name == "constructs" && class_name == "CClass" && method_name == "getField"
m->setPos( 450 , 500 );
module_name == "constructs" && class_name == "CIfElse" && method_name == "getHeader"
m->setPos( 450 , 0 );
module_name == "constructs" && class_name == "CIfElse" && method_name == "getThen"
m->setPos( 450 , 100 );
module_name == "constructs" && class_name == "CIfElse" && method_name == "getElse"
m->setPos( 450 , 200 );
module_name == "constructs" && class_name == "CLoop" && method_name == "getBody"
m->setPos( 450 , 100 );
module_name == "constructs" && class_name == "CLoop" && method_name == "getHeader"
m->setPos( 450 , 0 );
module_name == "constructs" && class_name == "CMethod" && method_name == "CMethod"
m->setPos( 0 , 0 );
module_name == "constructs" && class_name == "CMethod" && method_name == "getStatements"
m->setPos( 450 , 150 );
module_name == "constructs" && class_name == "CMethod" && method_name == "getArguments"
m->setPos( 450 , 50 );
module_name == "constructs" && class_name == "CModule" && method_name == "CModule"
m->setPos( 0 , 0 );
module_name == "constructs" && class_name == "CModule" && method_name == "getClasses"
m->setPos( 450 , 0 );
module_name == "constructs" && class_name == "CModule" && method_name == "getClass"
m->setPos( 450 , 100 );
module_name == "constructs" && class_name == "CPrompt" && method_name == "CPrompt"
m->setPos( 0 , 0 );
module_name == "constructs" && class_name == "CPrompt" && method_name == "getText"
m->setPos( 500 , 0 );
module_name == "constructs" && class_name == "CSequence" && method_name == "CSequence"
m->setPos( 0 , 0 );
module_name == "constructs" && class_name == "CSequence" && method_name == "~CSequence"
m->setPos( 350 , 0 );
module_name == "constructs" && class_name == "CSequence" && method_name == "getItems"
m->setPos( 1150 , 0 );
module_name == "constructs" && class_name == "CSequence" && method_name == "size"
m->setPos( 1150 , 250 );
module_name == "constructs" && class_name == "CSequence" && method_name == "operator[]"
m->setPos( 1150 , 100 );
module_name == "constructs" && class_name == "CSequence" && method_name == "insertNewAfter"
m->setPos( 0 , 300 );
module_name == "constructs" && class_name == "CSequence" && method_name == "insertNewBefore"
m->setPos( 0 , 700 );
module_name == "constructs" && class_name == "CSequence" && method_name == "remove"
m->setPos( 0 , 1100 );
module_name == "constructs" && class_name == "CSet" && method_name == "CSet"
m->setPos( 0 , 0 );
module_name == "constructs" && class_name == "CSet" && method_name == "~CSet"
m->setPos( 300 , 0 );
module_name == "constructs" && class_name == "CSet" && method_name == "getItems"
m->setPos( 1150 , 0 );
module_name == "constructs" && class_name == "CSet" && method_name == "size"
m->setPos( 1150 , 250 );
module_name == "constructs" && class_name == "CSet" && method_name == "operator[]"
m->setPos( 1150 , 100 );
module_name == "constructs" && class_name == "CSet" && method_name == "insertNew"
m->setPos( 0 , 300 );
module_name == "constructs" && class_name == "CStatement" && method_name == "CStatement"
m->setPos( 0 , 0 );
module_name == "constructs" && class_name == "CStatement" && method_name == "getText"
m->setPos( 400 , 0 );
module_name == "constructs" && class_name == "CText" && method_name == "CText"
m->setPos( 12 , 1 );
module_name == "constructs" && class_name == "CText" && method_name == "getText"
m->setPos( 350 , 0 );
module_name == "constructs" && class_name == "CText" && method_name == "setText"
m->setPos( 550 , 0 );
module_name == "constructs" && class_name == "CVariableDeclaration" && method_name == "getType"
m->setPos( 450 , 0 );
module_name == "helpers" && class_name == "Color" && method_name == "~Color"
m->setPos( 300 , 0 );
module_name == "helpers" && class_name == "Color" && method_name == "getColor"
m->setPos( 800 , 0 );
module_name == "helpers" && class_name == "Color" && method_name == "setColor"
m->setPos( 1050 , 0 );
module_name == "helpers" && class_name == "Name" && method_name == "Name"
m->setPos( 0 , 0 );
module_name == "helpers" && class_name == "Name" && method_name == "~Name"
m->setPos( 300 , 0 );
module_name == "helpers" && class_name == "Name" && method_name == "getName"
m->setPos( 650 , 0 );
module_name == "helpers" && class_name == "Position" && method_name == "Position"
m->setPos( 0 , 0 );
module_name == "helpers" && class_name == "Position" && method_name == "~Position"
m->setPos( 300 , 0 );
module_name == "helpers" && class_name == "Position" && method_name == "setPos"
m->setPos( 1150 , 0 );
module_name == "helpers" && class_name == "Position" && method_name == "setAutoPlacement"
m->setPos( 1150 , 200 );
module_name == "helpers" && class_name == "Position" && method_name == "getX"
m->setPos( 800 , 0 );
module_name == "helpers" && class_name == "Position" && method_name == "getY"
m->setPos( 800 , 100 );
module_name == "helpers" && class_name == "Position" && method_name == "isAutoPlaced"
m->setPos( 800 , 200 );
module_name == "helpers" && class_name == "Position" && method_name == "printPosition"
m->setPos( 400 , 600 );
module_name == "helpers" && class_name == "Position" && method_name == "printAll"
m->setPos( 0 , 600 );
module_name == "helpers" && class_name == "Visibility" && method_name == "Visibility"
m->setPos( 0 , 0 );
module_name == "helpers" && class_name == "Visibility" && method_name == "getVisibility"
m->setPos( 800 , 0 );
module_name == "helpers" && class_name == "Visibility" && method_name == "setVisibility"
m->setPos( 1050 , 0 );
module_name == "handlers" && class_name == "HApplication" && method_name == "HApplication"
m->setPos( 4 , 9 );
module_name == "handlers" && class_name == "HApplication" && method_name == "command"
m->setPos( 1600 , 150 );
module_name == "handlers" && class_name == "HApplication" && method_name == "getInstance"
m->setPos( 700 , 0 );
module_name == "handlers" && class_name == "HApplication" && method_name == "keyDigit"
m->setPos( 0 , 100 );
module_name == "handlers" && class_name == "HBase" && method_name == "HBase"
m->setPos( 21 , 1 );
module_name == "handlers" && class_name == "HBase" && method_name == "tokenize"
m->setPos( 2450 , 2000 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyLetter"
m->setPos( 600 , 1800 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyDigit"
m->setPos( 600 , 1650 );
module_name == "handlers" && class_name == "HBase" && method_name == "keySymbol"
m->setPos( 600 , 750 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyArrow"
m->setPos( 600 , 600 );
module_name == "handlers" && class_name == "HBase" && method_name == "keySpace"
m->setPos( 600 , 450 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyTab"
m->setPos( 600 , 900 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyShift"
m->setPos( 600 , 1050 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyControl"
m->setPos( 600 , 1200 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyAlt"
m->setPos( 600 , 1350 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyDelBackspace"
m->setPos( 600 , 1500 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyEnter"
m->setPos( 600 , 300 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyOther"
m->setPos( 600 , 1950 );
module_name == "handlers" && class_name == "HBase" && method_name == "buttonRelease"
m->setPos( 1300 , 1050 );
module_name == "handlers" && class_name == "HBase" && method_name == "mouseMove"
m->setPos( 1300 , 750 );
module_name == "handlers" && class_name == "HBase" && method_name == "processCommand"
m->setPos( 2500 , 350 );
module_name == "handlers" && class_name == "HBase" && method_name == "command"
m->setPos( 2500 , 200 );
module_name == "handlers" && class_name == "HBase" && method_name == "getInstance"
m->setPos( 600 , 0 );
module_name == "handlers" && class_name == "HBase" && method_name == "~HBase"
m->setPos( 200 , 0 );
module_name == "handlers" && class_name == "HBase" && method_name == "setView"
m->setPos( 1000 , 0 );
module_name == "handlers" && class_name == "HBase" && method_name == "view"
m->setPos( 600 , 100 );
module_name == "handlers" && class_name == "HBase" && method_name == "mouseMoveEvent"
m->setPos( 1300 , 250 );
module_name == "handlers" && class_name == "HBase" && method_name == "mouseReleaseEvent"
m->setPos( 1300 , 500 );
module_name == "handlers" && class_name == "HBase" && method_name == "keyPressEvent"
m->setPos( 0 , 300 );
module_name == "handlers" && class_name == "HClass" && method_name == "HClass"
m->setPos( 17 , 1 );
module_name == "handlers" && class_name == "HClass" && method_name == "command"
m->setPos( 850 , 150 );
module_name == "handlers" && class_name == "HClass" && method_name == "getInstance"
m->setPos( 450 , 0 );
module_name == "handlers" && class_name == "HClassField" && method_name == "keyEnter"
m->setPos( 0 , 100 );
module_name == "handlers" && class_name == "HClassField" && method_name == "keyControl"
m->setPos( 0 , 400 );
module_name == "handlers" && class_name == "HClassField" && method_name == "getInstance"
m->setPos( 900 , 0 );
module_name == "handlers" && class_name == "HGlobal" && method_name == "HGlobal"
m->setPos( 20 , 1 );
module_name == "handlers" && class_name == "HGlobal" && method_name == "command"
m->setPos( 800 , 50 );
module_name == "handlers" && class_name == "HGlobal" && method_name == "getInstance"
m->setPos( 400 , 0 );
module_name == "handlers" && class_name == "HIfElse" && method_name == "keyControl"
m->setPos( 0 , 200 );
module_name == "handlers" && class_name == "HIfElse" && method_name == "getInstance"
m->setPos( 500 , 0 );
module_name == "handlers" && class_name == "HMethodArgument" && method_name == "keyEnter"
m->setPos( 0 , 200 );
module_name == "handlers" && class_name == "HMethodArgument" && method_name == "keyControl"
m->setPos( 0 , 500 );
module_name == "handlers" && class_name == "HMethodArgument" && method_name == "getInstance"
m->setPos( 950 , 0 );
module_name == "handlers" && class_name == "HModule" && method_name == "HModule"
m->setPos( 17 , 1 );
module_name == "handlers" && class_name == "HModule" && method_name == "command"
m->setPos( 850 , 100 );
module_name == "handlers" && class_name == "HModule" && method_name == "getInstance"
m->setPos( 450 , 0 );
module_name == "handlers" && class_name == "HPrompt" && method_name == "HPrompt"
m->setPos( 15 , 9 );
module_name == "handlers" && class_name == "HPrompt" && method_name == "keyEnter"
m->setPos( 3 , 139 );
module_name == "handlers" && class_name == "HPrompt" && method_name == "buttonRelease"
m->setPos( 850 , 100 );
module_name == "handlers" && class_name == "HPrompt" && method_name == "getInstance"
m->setPos( 450 , 0 );
module_name == "handlers" && class_name == "HSequence" && method_name == "keyArrow"
m->setPos( 0 , 150 );
module_name == "handlers" && class_name == "HSequence" && method_name == "getInstance"
m->setPos( 950 , 0 );
module_name == "handlers" && class_name == "HStatement" && method_name == "HStatement"
m->setPos( 5 , 9 );
module_name == "handlers" && class_name == "HStatement" && method_name == "keyEnter"
m->setPos( 6 , 178 );
module_name == "handlers" && class_name == "HStatement" && method_name == "getInstance"
m->setPos( 450 , 0 );
module_name == "handlers" && class_name == "HText" && method_name == "adjustCursor"
m->setPos( 1650 , 1050 );
module_name == "handlers" && class_name == "HText" && method_name == "HText"
m->setPos( 15 , -9 );
module_name == "handlers" && class_name == "HText" && method_name == "keyLetter"
m->setPos( 0 , 900 );
module_name == "handlers" && class_name == "HText" && method_name == "keyArrow"
m->setPos( 0 , 1150 );
module_name == "handlers" && class_name == "HText" && method_name == "keyDelBackspace"
m->setPos( 0 , 200 );
module_name == "handlers" && class_name == "HText" && method_name == "buttonRelease"
m->setPos( 1200 , 200 );
module_name == "handlers" && class_name == "HText" && method_name == "getInstance"
m->setPos( 850 , 0 );
module_name == "handlers" && class_name == "UpdateEvent" && method_name == "UpdateEvent"
m->setPos( 250 , 0 );
module_name == "parsers" && class_name == "Parser" && method_name == "parseDir"
m->setPos( 0 , 750 );
module_name == "parsers" && class_name == "Parser" && method_name == "parseFile"
m->setPos( 0 , 1700 );
module_name == "parsers" && class_name == "Parser" && method_name == "removeComments"
m->setPos( 0 , 2950 );
module_name == "parsers" && class_name == "Parser" && method_name == "putOnNewLine"
m->setPos( 3200 , 2950 );
module_name == "parsers" && class_name == "Parser" && method_name == "normalizeParenthesis"
m->setPos( 2400 , 2950 );
module_name == "parsers" && class_name == "Parser" && method_name == "getLoopIfElseHeader"
m->setPos( 650 , 8500 );
module_name == "parsers" && class_name == "Parser" && method_name == "parseFileEntry"
m->setPos( 0 , 3800 );
module_name == "parsers" && class_name == "Parser" && method_name == "parseClassDeclaration"
m->setPos( 0 , 4850 );
module_name == "parsers" && class_name == "Parser" && method_name == "parseMethodArguments"
m->setPos( 0 , 7450 );
module_name == "parsers" && class_name == "Parser" && method_name == "parseBody"
m->setPos( 0 , 6500 );
module_name == "parsers" && class_name == "Parser" && method_name == "parseLoop"
m->setPos( 0 , 9100 );
module_name == "parsers" && class_name == "Parser" && method_name == "parseIfElse"
m->setPos( 0 , 8500 );
module_name == "parsers" && class_name == "Parser" && method_name == "createModule"
m->setPos( 5450 , -50 );
module_name == "parsers" && class_name == "Parser" && method_name == "createClass"
m->setPos( 5950 , -50 );
module_name == "parsers" && class_name == "Parser" && method_name == "createMethod"
m->setPos( 6750 , -50 );
module_name == "parsers" && class_name == "Parser" && method_name == "Parser"
m->setPos( 0 , 50 );
module_name == "parsers" && class_name == "Parser" && method_name == "~Parser"
m->setPos( 200 , 50 );
module_name == "parsers" && class_name == "Parser" && method_name == "getApp"
m->setPos( 0 , 400 );
module_name == "styles" && class_name == "SApplication" && method_name == "getNormalStyle"
m->setPos( 0 , 0 );
module_name == "styles" && class_name == "SApplication" && method_name == "getErrorStyle"
m->setPos( 0 , 350 );
module_name == "styles" && class_name == "SBox" && method_name == "SBox"
m->setPos( 7 , 5 );
module_name == "styles" && class_name == "SBox" && method_name == "~SBox"
m->setPos( 200 , 0 );
module_name == "styles" && class_name == "SBox" && method_name == "setPadding"
m->setPos( 0 , 350 );
module_name == "styles" && class_name == "SBox" && method_name == "setPadding"
m->setPos( 0 , 350 );
module_name == "styles" && class_name == "SBox" && method_name == "setShadowSize"
m->setPos( 0 , 1150 );
module_name == "styles" && class_name == "SBox" && method_name == "setTransparentBackground"
m->setPos( 0 , 700 );
module_name == "styles" && class_name == "SBox" && method_name == "setFadeBackground"
m->setPos( 0 , 100 );
module_name == "styles" && class_name == "SBox" && method_name == "setCorners"
m->setPos( 0 , 1000 );
module_name == "styles" && class_name == "SBox" && method_name == "setSnapToGrid"
m->setPos( 0 , 800 );
module_name == "styles" && class_name == "SClass" && method_name == "getNormalStyle"
m->setPos( 33 , 9 );
module_name == "styles" && class_name == "SClass" && method_name == "getErrorStyle"
m->setPos( 0 , 350 );
module_name == "styles" && class_name == "SClass" && method_name == "getTitleStyle"
m->setPos( 0 , 700 );
module_name == "styles" && class_name == "SClassName" && method_name == "getNormalStyle"
m->setPos( 0 , 0 );
module_name == "styles" && class_name == "SIfElse" && method_name == "getThenStyle"
m->setPos( 0 , 450 );
module_name == "styles" && class_name == "SIfElse" && method_name == "getElseStyle"
m->setPos( 0 , 800 );
module_name == "styles" && class_name == "SIfElse" && method_name == "getHeaderStyle"
m->setPos( 0 , 1400 );
module_name == "styles" && class_name == "SInvisible" && method_name == "getNormalStyle"
m->setPos( 1 , 25 );
module_name == "styles" && class_name == "SLoop" && method_name == "getErrorStyle"
m->setPos( 0 , 400 );
module_name == "styles" && class_name == "SLoop" && method_name == "getHeaderStyle"
m->setPos( 0 , 800 );
module_name == "styles" && class_name == "SMethod" && method_name == "getNormalStyle"
m->setPos( 5 , 5 );
module_name == "styles" && class_name == "SMethod" && method_name == "getErrorStyle"
m->setPos( 0 , 400 );
module_name == "styles" && class_name == "SMethod" && method_name == "getGrayStyle"
m->setPos( 550 , 0 );
module_name == "styles" && class_name == "SMethod" && method_name == "getHighlightStyle"
m->setPos( 550 , 450 );
module_name == "styles" && class_name == "SMethod" && method_name == "getSourceStyle"
m->setPos( 550 , 900 );
module_name == "styles" && class_name == "SMethod" && method_name == "getDestinationStyle"
m->setPos( 550 , 1300 );
module_name == "styles" && class_name == "SMethod" && method_name == "getStackTraceStyle"
m->setPos( 0 , 1200 );
module_name == "styles" && class_name == "SMethod" && method_name == "getTitleStyle"
m->setPos( 0 , 850 );
module_name == "styles" && class_name == "SModule" && method_name == "getErrorStyle"
m->setPos( 0 , 400 );
module_name == "styles" && class_name == "SModuleName" && method_name == "getHugeStyle"
m->setPos( 0 , 200 );
module_name == "styles" && class_name == "SPrompt" && method_name == "getNormalStyle"
m->setPos( 21 , -7 );
module_name == "styles" && class_name == "SPrompt" && method_name == "getErrorStyle"
m->setPos( 1 , 249 );
module_name == "styles" && class_name == "SStackTrace" && method_name == "getCallStatementStyle"
m->setPos( 650 , 0 );
module_name == "styles" && class_name == "SText" && method_name == "SText"
m->setPos( 0 , 0 );
module_name == "styles" && class_name == "SText" && method_name == "~SText"
m->setPos( 200 , 0 );
module_name == "styles" && class_name == "SVarInfo" && method_name == "getNormalStyle"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "ClassIcon" && method_name == "paint"
m->setPos( 0 , 300 );
module_name == "vis" && class_name == "ClassIcon" && method_name == "updateRepresentation"
m->setPos( 0 , 200 );
module_name == "vis" && class_name == "IfElseIcon" && method_name == "IfElseIcon"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "IfElseIcon" && method_name == "paint"
m->setPos( 0 , 300 );
module_name == "vis" && class_name == "IfElseIcon" && method_name == "updateRepresentation"
m->setPos( 0 , 200 );
module_name == "vis" && class_name == "LoopIcon" && method_name == "paint"
m->setPos( 0 , 300 );
module_name == "vis" && class_name == "LoopIcon" && method_name == "updateRepresentation"
m->setPos( 0 , 200 );
module_name == "vis" && class_name == "MethodIcon" && method_name == "MethodIcon"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "MethodIcon" && method_name == "paint"
m->setPos( 0 , 350 );
module_name == "vis" && class_name == "MethodIcon" && method_name == "updateRepresentation"
m->setPos( 0 , 250 );
module_name == "vis" && class_name == "VBase" && method_name == "updateIfConstructChanged"
m->setPos( 400 , 1450 );
module_name == "vis" && class_name == "VBase" && method_name == "updateAllChildren"
m->setPos( 0 , 2100 );
module_name == "vis" && class_name == "VBase" && method_name == "updateRepresentationFrame"
m->setPos( 0 , 1550 );
module_name == "vis" && class_name == "VBase" && method_name == "setEventHandler"
m->setPos( 1550 , 200 );
module_name == "vis" && class_name == "VBase" && method_name == "VBase"
m->setPos( 27 , 8 );
module_name == "vis" && class_name == "VBase" && method_name == "~VBase"
m->setPos( 450 , 0 );
module_name == "vis" && class_name == "VBase" && method_name == "updateModifiedItems"
m->setPos( 0 , 1900 );
module_name == "vis" && class_name == "VBase" && method_name == "focus"
m->setPos( 0 , 2450 );
module_name == "vis" && class_name == "VBase" && method_name == "focus"
m->setPos( 0 , 2450 );
module_name == "vis" && class_name == "VBase" && method_name == "setConsWithPrompt"
m->setPos( 0 , 1100 );
module_name == "vis" && class_name == "VBase" && method_name == "getCursor"
m->setPos( 1283 , 24 );
module_name == "vis" && class_name == "VBase" && method_name == "getHandler"
m->setPos( 1282 , 247 );
module_name == "vis" && class_name == "VBase" && method_name == "constructChanged"
m->setPos( 1250 , 1000 );
module_name == "vis" && class_name == "VBase" && method_name == "visualizationChanged"
m->setPos( 1250 , 1100 );
module_name == "vis" && class_name == "VBase" && method_name == "onChildChange"
m->setPos( 1250 , 1200 );
module_name == "vis" && class_name == "VBase" && method_name == "updateRepresentation"
m->setPos( 0 , 1450 );
module_name == "vis" && class_name == "VBase" && method_name == "getParent"
m->setPos( 1277 , 140 );
module_name == "vis" && class_name == "VBase" && method_name == "hasPrompt"
m->setPos( 0 , 1000 );
module_name == "vis" && class_name == "VBase" && method_name == "requestPrompt"
m->setPos( 0 , 500 );
module_name == "vis" && class_name == "VBase" && method_name == "removePrompt"
m->setPos( 650 , 500 );
module_name == "vis" && class_name == "VBase" && method_name == "showPrompt"
m->setPos( 0 , 800 );
module_name == "vis" && class_name == "VBase" && method_name == "showPrompt"
m->setPos( 0 , 800 );
module_name == "vis" && class_name == "VBase" && method_name == "HasFocusInHierarchy"
m->setPos( 350 , 2450 );
module_name == "vis" && class_name == "VBase" && method_name == "boundingRect"
m->setPos( 1275 , 338 );
module_name == "vis" && class_name == "VBase" && method_name == "type"
m->setPos( 1280 , 429 );
module_name == "vis" && class_name == "VBase" && method_name == "mouseMoveEvent"
m->setPos( 1250 , 1400 );
module_name == "vis" && class_name == "VBase" && method_name == "mouseReleaseEvent"
m->setPos( 1250 , 1550 );
module_name == "vis" && class_name == "VBase" && method_name == "keyPressEvent"
m->setPos( 1250 , 1700 );
module_name == "vis" && class_name == "VBox" && method_name == "roundedRect"
m->setPos( 0 , 1900 );
module_name == "vis" && class_name == "VBox" && method_name == "setClientSize"
m->setPos( 2450 , 600 );
module_name == "vis" && class_name == "VBox" && method_name == "itemChange"
m->setPos( 2050 , 1900 );
module_name == "vis" && class_name == "VBox" && method_name == "getClientWidth"
m->setPos( 2000 , 0 );
module_name == "vis" && class_name == "VBox" && method_name == "getClientHeight"
m->setPos( 2000 , 100 );
module_name == "vis" && class_name == "VBox" && method_name == "getPadding"
m->setPos( 2000 , 200 );
module_name == "vis" && class_name == "VBox" && method_name == "VBox"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VBox" && method_name == "setStyle"
m->setPos( 2450 , 450 );
module_name == "vis" && class_name == "VBox" && method_name == "getStyle"
m->setPos( 2000 , 300 );
module_name == "vis" && class_name == "VBox" && method_name == "paint"
m->setPos( 0 , 1550 );
module_name == "vis" && class_name == "VBox" && method_name == "setClient"
m->setPos( 2450 , 0 );
module_name == "vis" && class_name == "VBox" && method_name == "setHeader"
m->setPos( 2450 , 150 );
module_name == "vis" && class_name == "VBox" && method_name == "setIcon"
m->setPos( 2450 , 300 );
module_name == "vis" && class_name == "VBox" && method_name == "updateRepresentation"
m->setPos( 0 , 700 );
module_name == "vis" && class_name == "VBoxed" && method_name == "VBoxed"
m->setPos( 33 , 9 );
module_name == "vis" && class_name == "VClass" && method_name == "VClass"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VClassField" && method_name == "VClassField"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VClassField" && method_name == "getName"
m->setPos( 800 , 100 );
module_name == "vis" && class_name == "VClassField" && method_name == "getType"
m->setPos( 800 , 0 );
module_name == "vis" && class_name == "VDummy" && method_name == "VDummy"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VDummy" && method_name == "updateRepresentation"
m->setPos( 0 , 200 );
module_name == "vis" && class_name == "VDummy" && method_name == "get"
m->setPos( 500 , 0 );
module_name == "vis" && class_name == "VFields" && method_name == "clearAll"
m->setPos( 0 , 350 );
module_name == "vis" && class_name == "VFields" && method_name == "VFields"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VFields" && method_name == "~VFields"
m->setPos( 550 , 0 );
module_name == "vis" && class_name == "VFields" && method_name == "updateRepresentation"
m->setPos( 0 , 650 );
module_name == "vis" && class_name == "VFields" && method_name == "paint"
m->setPos( 0 , 1300 );
module_name == "vis" && class_name == "VGrid" && method_name == "removeAllItems"
m->setPos( 0 , 150 );
module_name == "vis" && class_name == "VGrid" && method_name == "VGrid"
m->setPos( 23 , -4 );
module_name == "vis" && class_name == "VGrid" && method_name == "~VGrid"
m->setPos( 250 , 0 );
module_name == "vis" && class_name == "VGrid" && method_name == "setXY"
m->setPos( 2350 , 0 );
module_name == "vis" && class_name == "VGrid" && method_name == "getX"
m->setPos( 2150 , 100 );
module_name == "vis" && class_name == "VGrid" && method_name == "getY"
m->setPos( 2150 , 0 );
module_name == "vis" && class_name == "VGrid" && method_name == "setItem"
m->setPos( 2350 , 550 );
module_name == "vis" && class_name == "VGrid" && method_name == "removeItem"
m->setPos( 400 , 150 );
module_name == "vis" && class_name == "VGrid" && method_name == "updateRepresentation"
m->setPos( 0 , 500 );
module_name == "vis" && class_name == "VIfElse" && method_name == "switchFocus"
m->setPos( 0 , 650 );
module_name == "vis" && class_name == "VIfElse" && method_name == "getThen"
m->setPos( 1400 , 0 );
module_name == "vis" && class_name == "VIfElse" && method_name == "getElse"
m->setPos( 1400 , 100 );
module_name == "vis" && class_name == "VLinear" && method_name == "removeAllItems"
m->setPos( 300 , 1300 );
module_name == "vis" && class_name == "VLinear" && method_name == "setOptions"
m->setPos( 1400 , 0 );
module_name == "vis" && class_name == "VLinear" && method_name == "addItem"
m->setPos( 0 , 1300 );
module_name == "vis" && class_name == "VLinear" && method_name == "updateRepresentation"
m->setPos( 0 , 400 );
module_name == "vis" && class_name == "VLoop" && method_name == "paint"
m->setPos( 0 , 400 );
module_name == "vis" && class_name == "VMethod" && method_name == "VMethod"
m->setPos( -7 , -1 );
module_name == "vis" && class_name == "VMethod" && method_name == "getStatements"
m->setPos( 550 , 0 );
module_name == "vis" && class_name == "VMethodArgument" && method_name == "VMethodArgument"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VMethodArgument" && method_name == "VMethodArgument"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VMethodArgument" && method_name == "getName"
m->setPos( 800 , 0 );
module_name == "vis" && class_name == "VMethodArgument" && method_name == "getType"
m->setPos( 800 , 100 );
module_name == "vis" && class_name == "VModule" && method_name == "VModule"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VModule" && method_name == "updateRepresentation"
m->setPos( 0 , 400 );
module_name == "vis" && class_name == "VModule" && method_name == "switchBigNames"
m->setPos( 0 , 300 );
module_name == "vis" && class_name == "VPrompt" && method_name == "focus"
m->setPos( 0 , 300 );
module_name == "vis" && class_name == "VRuntimeVariableInfo" && method_name == "VRuntimeVariableInfo"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VRuntimeVariableInfo" && method_name == "getName"
m->setPos( 800 , 0 );
module_name == "vis" && class_name == "VRuntimeVariableInfo" && method_name == "getVInfo"
m->setPos( 800 , 100 );
module_name == "vis" && class_name == "VRuntimeVariableInfo" && method_name == "getCInfo"
m->setPos( 800 , 200 );
module_name == "vis" && class_name == "VSequence" && method_name == "removeAllItems"
m->setPos( 500 , 1500 );
module_name == "vis" && class_name == "VSequence" && method_name == "isConstructIdentityChanged"
m->setPos( 0 , 1500 );
module_name == "vis" && class_name == "VSequence" && method_name == "VSequence"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VSequence" && method_name == "~VSequence"
m->setPos( 500 , 0 );
module_name == "vis" && class_name == "VSequence" && method_name == "getItems"
m->setPos( 1100 , 0 );
module_name == "vis" && class_name == "VSequence" && method_name == "size"
m->setPos( 1100 , 100 );
module_name == "vis" && class_name == "VSequence" && method_name == "operator[]"
m->setPos( 1100 , 200 );
module_name == "vis" && class_name == "VSequence" && method_name == "setSequenceOptions"
m->setPos( 1350 , 0 );
module_name == "vis" && class_name == "VSequence" && method_name == "updateRepresentation"
m->setPos( 0 , 400 );
module_name == "vis" && class_name == "VSet" && method_name == "removeAllItems"
m->setPos( 0 , 350 );
module_name == "vis" && class_name == "VSet" && method_name == "VSet"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VSet" && method_name == "~VSet"
m->setPos( 400 , 0 );
module_name == "vis" && class_name == "VSet" && method_name == "updateRepresentation"
m->setPos( 0 , 550 );
module_name == "vis" && class_name == "VSpacer" && method_name == "updateRepresentation"
m->setPos( 0 , 300 );
module_name == "vis" && class_name == "VSpacer" && method_name == "paint"
m->setPos( 0 , 200 );
module_name == "vis" && class_name == "VSpacer" && method_name == "setSize"
m->setPos( 0 , 400 );
module_name == "vis" && class_name == "VStackTrace" && method_name == "clearAll"
m->setPos( 0 , 1200 );
module_name == "vis" && class_name == "VStackTrace" && method_name == "highlightStatement"
m->setPos( 550 , 400 );
module_name == "vis" && class_name == "VStackTrace" && method_name == "VStackTrace"
m->setPos( 0 , 0 );
module_name == "vis" && class_name == "VStackTrace" && method_name == "~VStackTrace"
m->setPos( 400 , 0 );
module_name == "vis" && class_name == "VStackTrace" && method_name == "addMethod"
m->setPos( 0 , 400 );
module_name == "vis" && class_name == "VStackTrace" && method_name == "addVarInfo"
m->setPos( 0 , 950 );
module_name == "vis" && class_name == "VStatement" && method_name == "getText"
m->setPos( 550 , 0 );
module_name == "vis" && class_name == "VText" && method_name == "VText"
m->setPos( 7 , 13 );
module_name == "vis" && class_name == "VText" && method_name == "paint"
m->setPos( 0 , 400 );
module_name == "vis" && class_name == "VText" && method_name == "updateRepresentation"
m->setPos( 0 , 700 );
module_name == "vis" && class_name == "VText" && method_name == "setStyle"
m->setPos( 900 , 0 );
module_name == "vis_helpers" && class_name == "VisFactory" && method_name == "getNewStatementVis"
m->setPos( 0 , 0 );
return m;
Parser ~Parser
getApp pathQString
app = new CApplication(NULL);QDir dir(path);
dir.dirName() != "."
app->getName().setText(dir.dirName());
qDebug() << "Parsing application " << dir.dirName();parseDir(path);return app;
Parserparsers
normal static SApplication*error static SApplication*
getNormalStyle
!normal
normal = new SApplication();normal->border.setWidth(6);normal->setCorners(20, false);normal->setShadowSize(15);normal->setPadding(60);normal->background.setColor( Qt::white );
return normal;
getErrorStyle
!error
error = new SApplication();error->border.setWidth(6);error->setCorners(20, false);error->setShadowSize(15);error->setPadding(60);error->setFadeBackground(Qt::white, Qt::red);
return error;
SApplication
background QBrushborder QPenshadow QBrushcorner_radius intshadow_x intshadow_y intpadding_top intpadding_left intpadding_bottom intpadding_right inticon_distance intheader_distance intcut_corners boolheader_centered boolsnap_to_grid int
SBox ~SBox
setPadding paddingint
topint
left int
bottom int
right int
padding_top = padding;padding_left = padding;padding_bottom = padding;padding_right = padding;padding_top = top;padding_left = left;padding_bottom = bottom;padding_right = right;
setPadding
setShadowSize sizeint
shadow_x = size;shadow_y = size;
setTransparentBackground
background = QBrush(QColor(Qt::transparent));
setFadeBackground topQColor
bottom QColor
QLinearGradient gradient(0, 0, 0, 200);gradient.setColorAt(0, top);gradient.setColorAt(1, bottom);background = QBrush(gradient);
setCorners radiusint
cut bool
corner_radius = radius;cut_corners = cut;
setSnapToGrid grid_sizeint
grid_size >= 0
snap_to_grid = grid_size;
SBox
normal static SClass*error static SClass*title static SBox*
100 static const int GRID_SIZE =
getNormalStyle
!normal
normal = new SClass();normal->border.setWidth(3);normal->setCorners(5, false);normal->setShadowSize(0);normal->setPadding(20);normal->background.setColor(QColor(0xFF,0xFF,0xFF,0xC0));normal->setSnapToGrid(GRID_SIZE);
return normal;
getErrorStyle
!error
error = new SClass();error->border.setWidth(3);error->setCorners(5, false);error->setShadowSize(0);error->setPadding(20);error->setFadeBackground(Qt::white, Qt::red);error->setSnapToGrid(GRID_SIZE);
return error;
getTitleStyle
!title
title = new SBox();title->border.setWidth(2);title->setCorners(15, false);title->setShadowSize(0);title->setPadding(5);
return title;
SClass
normal static SClassName*
getNormalStyle
!normal
normal = new SClassName();normal->font.setPixelSize(24);normal->font.setFamily("Times");normal->font.setItalic(true);normal->font.setBold(true);normal->pen.setColor(Qt::blue);
return normal;
SClassName
normal static SIfElse*then_branch static SIfElse*_branch _branchheader static SBox*
getNormalStyle
!normal
normal = new SIfElse();normal->border.setWidth(1);normal->border.setColor(Qt::gray);normal->setCorners(2, true);normal->setShadowSize(0);normal->setPadding(2);normal->padding_left = 10;normal->background.setColor(Qt::white);normal->background.setColor(QColor(0xFF, 0xFF, 0xFF, 0x40));normal->header_centered = false;
return normal;
getThenStyle
!then_branch
then_branch = new SIfElse();then_branch->border.setStyle(Qt::NoPen);then_branch->setCorners(2, true);then_branch->setShadowSize(0);then_branch->setPadding(2);then_branch->background.setColor(QColor(0xD0, 0xFF, 0xD0, 0xA0));
return then_branch;
getElseStyle
!else_branch
else_branch = new SIfElse();else_branch->border.setStyle(Qt::NoPen);else_branch->setCorners(2, true);else_branch->setShadowSize(0);else_branch->setPadding(2);else_branch->background.setColor(QColor(0xFF, 0xD0, 0xD0, 0xA0));
returnelse_branch;
getHeaderStyle
!header
header = new SBox();header->border.setWidth(1);header->border.setColor(Qt::gray);header->setCorners(4, true);header->setShadowSize(0);header->setPadding(2);header->background.setColor(Qt::white);
return header;
SIfElse
normal static SInvisible*
getNormalStyle
!normal
normal = new SInvisible();normal->border = QPen(Qt::NoPen);normal->setShadowSize(0);normal->setPadding(1);normal->header_distance = 0;normal->setTransparentBackground();
return normal;
SInvisible
normal static SLoop*error static SLoop*header static SBox*
getNormalStyle
!normal
normal = new SLoop();normal->border.setWidth(1);normal->border.setColor(QColor(0x80,0x80,0xFF));normal->setCorners(2, true);normal->setShadowSize(0);normal->setPadding(10);normal->setFadeBackground(QColor(Qt::white), QColor(0xD0, 0xD0, 0xFF));normal->header_centered = false;
return normal;
getErrorStyle
!error
error = new SLoop();error->border.setWidth(1);error->border.setColor(Qt::red);error->setCorners(2, true);error->setShadowSize(0);error->setPadding(10);error->background.setColor(Qt::red);error->header_centered = false;
return error;
getHeaderStyle
!header
header = new SBox();header->border.setWidth(1);header->border.setColor(Qt::gray);header->setCorners(5, false);header->setShadowSize(0);header->setPadding(2);header->background.setColor(Qt::white);
return header;
SLoop
normal static SMethod*error static SMethod*gray static SMethod*highlight static SMethod*source static SMethod*destination static SMethod*stack_trace static SMethod*title static SBox*
50 static const int GRID_SIZE =
getNormalStyle
!normal
normal = new SMethod();normal->border.setWidth(2);normal->setCorners(15, false);normal->setShadowSize(0);normal->setPadding(5);normal->header_centered = false;normal->background.setColor(Qt::white);normal->setSnapToGrid(GRID_SIZE);
return normal;
getErrorStyle
!error
error = new SMethod();error->border.setWidth(2);error->border.setColor(Qt::red);error->setCorners(15, false);error->setShadowSize(0);error->setPadding(5);error->header_centered = false;error->background.setColor(Qt::red);error->setSnapToGrid(GRID_SIZE);
return error;
getGrayStyle
!gray
gray = new SMethod();gray->border.setWidth(1);gray->border.setColor(Qt::lightGray);gray->setCorners(15, false);gray->setShadowSize(0);gray->setPadding(5);gray->header_centered = false;gray->setFadeBackground(QColor(0xFF, 0xFF, 0xFF, 0x00), QColor(0xC0, 0xC0, 0xC0, 0x80));gray->setSnapToGrid(GRID_SIZE);
return gray;
getHighlightStyle
!highlight
highlight = new SMethod();highlight->border.setWidth(4);highlight->border.setColor(Qt::green);highlight->setCorners(15, false);highlight->setShadowSize(6);highlight->setPadding(5);highlight->header_centered = false;highlight->background.setColor( QColor(0x40, 0x40, 0xFF) );highlight->setSnapToGrid(GRID_SIZE);
return highlight;
getSourceStyle
!source
source = new SMethod();source->border.setWidth(2);source->setCorners(15, false);source->setShadowSize(0);source->setPadding(5);source->header_centered = false;source->background.setColor( QColor(0x40, 0xFF, 0x40) );source->setSnapToGrid(GRID_SIZE);
return source;
getDestinationStyle
!destination
destination = new SMethod();destination->border.setWidth(2);destination->setCorners(15, false);destination->setShadowSize(0);destination->setPadding(5);destination->header_centered = false;destination->background.setColor( QColor(0xFF, 0x40, 0x40) );destination->setSnapToGrid(GRID_SIZE);
return destination;
getStackTraceStyle
!stack_trace
stack_trace = new SMethod();stack_trace->border.setWidth(2);stack_trace->setCorners(15, false);stack_trace->setShadowSize(0);stack_trace->setPadding(5);stack_trace->header_centered = false;stack_trace->background.setColor(Qt::white);
return stack_trace;
getTitleStyle
!title
title = new SBox();title->border.setWidth(2);title->setCorners(7, true);title->setShadowSize(0);title->setPadding(5);title->header_centered = false;
return title;
SMethod
normal static SMethodName*
getNormalStyle
!normal
normal = new SMethodName();normal->font.setPixelSize(20);normal->font.setBold(true);
return normal;
SMethodName
normal static SModule*error static SModule*
500 static const int GRID_SIZE =
getNormalStyle
!normal
normal = new SModule();normal->border.setWidth(4);normal->setCorners(6, true);normal->setShadowSize(0);normal->setPadding(15);normal->padding_top = 30;normal->background.setColor(Qt::lightGray);normal->setSnapToGrid(GRID_SIZE);
return normal;
getErrorStyle
!error
error = new SModule();error->border.setWidth(4);error->setCorners(6, true);error->setShadowSize(0);error->setPadding(15);error->padding_top = 30;error->setFadeBackground(Qt::white, Qt::red);error->setSnapToGrid(GRID_SIZE);
return error;
SModule
normal static SModuleName*huge static SModuleName*
getNormalStyle
!normal
normal = new SModuleName();normal->font.setBold(true);
return normal;
getHugeStyle
!huge
huge = new SModuleName();huge->font.setPointSize(400);
return huge;
SModuleName
normal static SPrompt*error static SPrompt*
getNormalStyle
!normal
normal = new SPrompt();normal->background.setColor(QColor(0xFF, 0xCC, 0x33));
return normal;
getErrorStyle
!error
error = new SPrompt();error->border.setColor(Qt::red);error->background.setColor(QColor(0xFF, 0xA0, 0xA0));
return error;
SPrompt
normal static SStackTrace*call_statement static SBox*
getNormalStyle
!normal
normal = new SStackTrace();normal->border.setWidth(2);normal->setCorners(15, false);normal->setShadowSize(10);normal->setPadding(10);normal->header_centered = true;normal->setFadeBackground(Qt::white, QColor(0xFF, 0xA0, 0xA0) );
return normal;
getCallStatementStyle
!call_statement
call_statement = new SBox();call_statement->border = QPen(Qt::NoPen);call_statement->background.setColor(QColor(0xFF, 0xA0, 0x00));call_statement->setShadowSize(0);call_statement->setPadding(1);
return call_statement;
SStackTrace
font QFontpen QPen
SText
font.setPixelSize(20);
~SText
SText
normal static SType*
getNormalStyle
!normal
normal = new SType();normal->font.setItalic(true);normal->pen.setColor(Qt::blue);
return normal;
SType
normal static SVarInfo*
getNormalStyle
!normal
normal = new SVarInfo();normal->font.setItalic(true);normal->pen.setColor(Qt::darkYellow);
return normal;
SVarInfo
styles
ClassIcon parentVBase*
updateRepresentation();
paint painterQPainter*
option const QStyleOptionGraphicsItem*
widget QWidget*
QRadialGradient gradient(SIZE / 2, SIZE / 2, SIZE/2, SIZE / 2, SIZE / 2);gradient.setColorAt(0, Qt::white);gradient.setColorAt(1, Qt::transparent);painter->setBrush(QBrush(gradient));QPen p(Qt::NoPen);painter->setPen(p);painter->drawRect(0,0,SIZE,SIZE);painter->setBrush(Qt::white);QPen pen(Qt::black, 1);painter->setPen(pen);int width = SIZE / 2 - 4;int height = SIZE / 3;painter->drawRect((SIZE - width) / 2, 2, width, height);painter->drawRect(1, SIZE - 2 - height, width, height);painter->drawRect(SIZE - 1 - width, SIZE - 2 - height, width, height);painter->drawLine(1 + width / 2, SIZE / 2, SIZE - 1 - width / 2, SIZE / 2);painter->drawLine(SIZE / 2, 2 + height, SIZE / 2, SIZE / 2);painter->drawLine(1 + width / 2, SIZE / 2, 1 + width / 2, SIZE - 2 - height);painter->drawLine(SIZE - 1 - width / 2, SIZE / 2, SIZE - 1 - width / 2, SIZE - 2 - height);
updateRepresentation
bounding_rect = QRectF(0, 0, SIZE, SIZE);
ClassIcon
IfElseIcon parentVBase*
updateRepresentation();
paint painterQPainter*
option const QStyleOptionGraphicsItem*
widget QWidget*
QPainterPath p;p.moveTo(SIZE/2 , 1);p.lineTo(1, SIZE/2);p.lineTo(SIZE/2, SIZE - 1);p.lineTo(SIZE - 1, SIZE/2);p.closeSubpath();QLinearGradient gradient(5,5,20,20);gradient.setColorAt(0, Qt::white);gradient.setColorAt(1, Qt::yellow);painter->setBrush( QBrush(gradient) );QPen pen(Qt::black, 1);painter->setPen(pen);painter->drawPath(p);
updateRepresentation
bounding_rect = QRectF(0, 0, SIZE, SIZE);
IfElseIcon
LoopIcon parentVBase*
updateRepresentation();
paint painterQPainter*
option const QStyleOptionGraphicsItem*
widget QWidget*
QPainterPath p;p.moveTo(SIZE - ARROW_WING - 1, SIZE / 2 - 1);p.arcTo(ARROW_WING, 1, SIZE - ARROW_WING - 1, SIZE-2, 5, 150);p.lineTo(1, SIZE/2 - (4*ARROW_WING)/3 - 1);p.lineTo(2*ARROW_WING+1, SIZE/2 - 1);p.lineTo(4*ARROW_WING+1, SIZE/2 - (4*ARROW_WING)/3 - 1);p.arcTo(3*ARROW_WING - ARROW_WING/3 - 1, ARROW_WING, SIZE - 4*ARROW_WING , SIZE - ARROW_WING, 143, -130);p.closeSubpath();QLinearGradient gradient(0,0,20,20);gradient.setColorAt(0, QColor(Qt::white));gradient.setColorAt(1, QColor(0x80,0x80,0xFF));painter->setBrush( QBrush(gradient) );QPen pen(Qt::black, 1);painter->setPen(pen);painter->drawPath(p);painter->rotate(180);painter->translate(-SIZE - 6, -SIZE);painter->drawPath(p);
updateRepresentation
bounding_rect = QRectF(0, 0, BOUNDARY, BOUNDARY);
LoopIcon
MethodIcon parentVBase*
updateRepresentation();
paint painterQPainter*
option const QStyleOptionGraphicsItem*
widget QWidget*
QPainterPath p;int step = 360 / (2 * NUM_TEETH);int i = 0;
int degree = step / 2; degree < 360; degree += step
int len;float x, y;len = (i % 2) ? MID_RADIUS : OUT_RADIUS;x = SIZE / 2 + len * cos(degree * (PI / 180.0));y = SIZE / 2 + len * sin(degree * (PI / 180.0));
degree == step / 2
p.moveTo(x, y); p.lineTo(x, y);
len = (i % 2) ? OUT_RADIUS : MID_RADIUS;x = SIZE / 2 + len * cos(degree * (PI / 180.0));y = SIZE / 2 + len * sin(degree * (PI / 180.0));p.lineTo(x, y);i = (i + 1);
p.closeSubpath();p.addEllipse(SIZE / 2 - IN_RADIUS, SIZE / 2- IN_RADIUS, 2 * IN_RADIUS, 2 * IN_RADIUS);QPen pen(Qt::black);painter->setBrush(Qt::gray);pen.setWidth(1);painter->setPen(pen);painter->scale(0.6, 0.6);painter->drawPath(p);painter->translate(SIZE/2 + 5,SIZE/2 + 5);painter->drawPath(p);
updateRepresentation
bounding_rect = QRectF(0, 0, SIZE, SIZE);
MethodIcon
app CApplication*modules VSet<CModule, VModule>name VText
VApplication parentVBase*
app CApplication*
setEventHandler( HApplication::getInstance());setStyle( SApplication::getNormalStyle() );setClient( &modules );name.setPos(15,15);
VApplication
parent VBase*handler HBase*revision intis_updating_rep boolis_updating_cons booldefault_handler static HBase*vis_prompt static VPrompt*cons_prompt static CPrompt*need_updating static std::list<VBase*>focused_vis static VBase*focused_cons static Construct*cons_with_prompt static Construct*
bounding_rect QRectFcursor static Cursor
updateIfConstructChanged
getConstruct() == NULL || revision != getConstruct()->getRevision()
is_updating_cons = true;updateAllChildren();Position* p = dynamic_cast<Position*> (getConstruct());
p && p->isAutoPlaced() == false
setPos(p->getX(), p->getY());
updateRepresentationFrame();getConstruct()
revision = getConstruct()->getRevision();
is_updating_cons = false;
updateAllChildren
int i = 0; i < children().length(); ++i
VBase* child = dynamic_cast<VBase*> ((children())[i]);child
child->updateIfConstructChanged();
updateRepresentationFrame
is_updating_rep == false
is_updating_rep = true;prepareGeometryChange();updateRepresentation();is_updating_rep = false;
parent
parent->onChildChange(this);
setEventHandler handlerHBase*
this->handler = handler;
VBase parentVBase*
cons Construct*
cons != NULL && cons == cons_with_prompt
showPrompt();setConsWithPrompt( NULL);
cons != NULL && cons == focused_cons
setFlag(ItemIsFocusable);setFocus();
~VBase
vis_prompt && vis_prompt->getParent() == this
removePrompt();
scene()
scene()->removeItem(this);
need_updating.remove( this );
updateModifiedItems
std::list<VBase*>::iterator it = need_updating.begin(); it != need_updating.end(); ++it
(*it)->updateIfConstructChanged();
need_updating.clear();
focus visVBase*
consConstruct*
focused_cons = NULL;focused_vis = vis;focused_vis = NULL;focused_cons = cons;
focus
setConsWithPrompt consConstruct*
cons_with_prompt = cons;focused_cons = NULL;focused_vis = NULL;
getCursor
return cursor;
getHandler
return handler;
constructChanged
need_updating.push_back(this);
visualizationChanged
updateRepresentationFrame();
onChildChange childVBase*
!is_updating_rep && !is_updating_cons
updateRepresentationFrame();
updateRepresentation
getParent
return parent;
hasPrompt
return vis_prompt != NULL && vis_prompt->getParent() == this;
requestPrompt
!hasPrompt()
removePrompt();cons_prompt = new CPrompt(NULL);focus(&cons_prompt->getText());vis_prompt = new VPrompt(this, cons_prompt);cursor.pos = 0;
vis_prompt->focus();
return vis_prompt;
removePrompt
vis_prompt != NULL
delete vis_prompt;vis_prompt = NULL;delete cons_prompt;cons_prompt = NULL;
showPrompt xint
y int
requestPrompt();vis_prompt->setPos(x - vis_prompt->bounding_rect.width() / 2, y - vis_prompt->bounding_rect.height() / 2);
bounding_rect.width() > 0
showPrompt(bounding_rect.width() / 2, bounding_rect.height() / 2); showPrompt(50, 50);
showPrompt
getPromptCons
return cons_prompt;
HasFocusInHierarchy
bool has_focus = hasFocus();!has_focus
int i = 0; i < children().length(); ++i
VBase* child = dynamic_cast<VBase*> ((children())[i]);child
has_focus = child->HasFocusInHierarchy();
has_focus
break;
return has_focus;
boundingRect
return bounding_rect;
type
return Type;
mouseMoveEvent eventQGraphicsSceneMouseEvent*
QGraphicsItem::mouseMoveEvent(event);handler->mouseMoveEvent(event, this);
mouseReleaseEvent eventQGraphicsSceneMouseEvent*
handler->mouseReleaseEvent(event, this);QGraphicsItem::mouseReleaseEvent(event);
keyPressEvent eventQKeyEvent*
handler->keyPressEvent(event, this);
VBase
client_width intclient_height intheader_width intheader_height inticon_width inticon_height intoutter_width intoutter_height intsnap_to_grid intclient VBase*header VBase*icon VBase*style SBox*default_style static SBox
roundedRect xint
y int
width int
height int
radius int
cut_edges bool
QPainterPath path;path.moveTo(width + x, radius + y);
cut_edges
path.lineTo(width + x - radius, y); path.arcTo(width - 2 * radius + x, y, radius * 2, radius * 2, 0.0, 90.0);
path.lineTo(radius + x, y);cut_edges
path.lineTo(x, radius + y); path.arcTo(x, y, radius * 2, radius * 2, 90.0, 90.0);
path.lineTo(x, height - radius + y);cut_edges
path.lineTo(x + radius, height + y); path.arcTo(x, height - 2 * radius + y, radius * 2, radius * 2, 180.0, 90.0);
path.lineTo(width - radius + x, height + y);cut_edges
path.lineTo(x + width, height - radius + y); path.arcTo(width - 2 * radius + x, height - 2 * radius + y, radius * 2, radius * 2, 270.0, 90.0);
path.closeSubpath();return path;
setClientSize widthint
height int
width >= 0
client_width = width;
height >= 0
client_height = height;
itemChange changeGraphicsItemChange
&value const QVariant
change == ItemPositionChange && style->snap_to_grid > 0
QPointF newPos = value.toPointF();newPos.setX(((int) (newPos.x() / style->snap_to_grid)) * style->snap_to_grid);newPos.setY(((int) (newPos.y() / style->snap_to_grid)) * style->snap_to_grid);return newPos;
return QGraphicsItem::itemChange(change, value);
getClientWidth
return client_width;
getClientHeight
return client_height;
getPadding
return style->padding_top;
VBox parentVBase*
cons Construct*
setFlag(ItemIsMovable);setFlag(ItemIsFocusable);setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);setZValue(5);client_width = 0;client_height = 0;header_width = 0;header_height = 0;icon_width = 0;icon_height = 0;updateRepresentation();
setStyle styleSBox*
style = style_;updateRepresentation();
getStyle
return style;
paint painterQPainter*
option const QStyleOptionGraphicsItem*
widget QWidget*
int half_header = std::max(header_height,icon_height) / 2;style->shadow_x > 0 || style->shadow_y > 0
painter->setPen(Qt::NoPen);painter->setBrush(style->shadow);painter->drawPath(roundedRect(style->shadow_x, half_header + style->shadow_y, outter_width+ style->border.width(), outter_height + style->border.width(), style->corner_radius, style->cut_corners));
painter->setBrush(style->background);painter->setPen(style->border);int half_border = (style->border.width() + 1) / 2;painter->drawPath(roundedRect(half_border, half_header + half_border, outter_width, outter_height,style->corner_radius, style->cut_corners));
setClient clientVBase*
this->client = client;updateRepresentation();
setHeader headerVBase*
this->header = header;updateRepresentation();
setIcon iconVBase*
this->icon = icon;updateRepresentation();
updateRepresentation
client
client_width = client->boundingRect().width();client_height = client->boundingRect().height();
header
header_width = header->boundingRect().width();header_height = header->boundingRect().height();
icon
icon_width = icon->boundingRect().width();icon_height = icon->boundingRect().height();
int max_width = std::max(client_width, header_width + icon_width + style->icon_distance - style->padding_left);outter_width = std::max(max_width + style->padding_left + style->padding_right, 2 * style->corner_radius);int header_icon_height = std::max(header_height, icon_height);int top_distance = std::max(style->padding_top, header_icon_height / 2 + style->header_distance);outter_height = std::max(top_distance + client_height + style->padding_bottom, 2 * style->corner_radius);int adjust_x = style->border.width() + style->shadow_x;int adjust_y = style->border.width() + style->shadow_y;bounding_rect = QRectF(0, 0, outter_width + adjust_x, outter_height + adjust_y + (int) (header_icon_height / 2));
icon
icon->setPos(0, (header_icon_height - icon_height) / 2);
header
style->header_centered
header->setPos(icon_width + (bounding_rect.width() - icon_width - header_width) / 2,(header_icon_height - header_height) / 2); header->setPos(icon_width + style->icon_distance, (header_icon_height - header_height) / 2);
client
client->setPos(style->padding_left, header_icon_height / 2 + top_distance);
VBox
item V
VBoxed parentVBase*
cons C*
setClient(&item);
VBoxed
cclass CClass*icon ClassIconcontents VLinear<VBase>fields VFieldsmethods VSet<CMethod, VMethod>name VBoxed<VText,CText>
VClass parentVBase*
cclass CClass*
setEventHandler(HClass::getInstance());name.item.setStyle(SClassName::getNormalStyle());setStyle(SClass::getNormalStyle());name.setStyle(SClass::getTitleStyle());contents.setOptions(true,false, 10);contents.addItem(&fields);contents.addItem(&methods);setClient(&contents);setHeader(&name);setIcon(&icon);
VClass
dec CVariableDeclaration*v VLinear<VText>name VTexttype VText
VClassField parentVBase*
dec CVariableDeclaration*
setEventHandler(HClassField::getInstance());name.setZValue(v.zValue() + 1);type.setZValue(v.zValue() + 1);type.setStyle(SType::getNormalStyle());v.setOptions(false, false, 5);v.addItem(&name);v.addItem(&type);setStyle(SInvisible::getNormalStyle());setClient(&v);
getName
return name;
getType
return type;
VClassField
construct T*
VDummy parentVBase*
cons T*
bounding_rect.setCoords(0,0,0,0);
updateRepresentation
get
return construct;
VDummy
fields CSet<CVariableDeclaration>*sections VLinear<VBase>sec_private VLinear<VBase>sec_public VLinear<VBase>sec_protected VLinear<VBase>vis_fields std::list<VClassField*>
clearAll
sections.removeAllItems();sec_private.removeAllItems();sec_public.removeAllItems();sec_protected.removeAllItems();
std::list<VClassField*>::iterator it = vis_fields.begin(); it != vis_fields.end(); ++it
delete (*it);
vis_fields.clear();
VFields parentVBase*
fields CSet<CVariableDeclaration>*
sections.setOptions(false, false, DISTANCE);setClient(§ions);updateRepresentation();
~VFields
clearAll();
updateRepresentation
vis_fields.size() != fields->size()
clearAll();
int i = 0; i < fields->size(); ++i
VClassField* v;(*fields)[i]->getVisibility() == Visibility::PRIVATE
v = new VClassField(&sec_private, (*fields)[i]);sec_private.addItem(v);
(*fields)[i]->getVisibility() == Visibility::PUBLIC
v = new VClassField(&sec_public, (*fields)[i]);sec_public.addItem(v);
(*fields)[i]->getVisibility() == Visibility::PROTECTED
v = new VClassField(&sec_protected, (*fields)[i]);sec_protected.addItem(v);
vis_fields.push_back(v);
sections.addItem(&sec_public);sections.addItem(&sec_protected);sections.addItem(&sec_private);
VBox::updateRepresentation();paint painter
QPainter*option
const QStyleOptionGraphicsItem*widget
QWidget*
VBox::paint(painter, option, widget);QPen pen(Qt::black);QVector<qreal> dashes;dashes << 5 << 10;pen.setDashPattern(dashes);pen.setWidth(1);painter->setPen(pen);painter->drawLine(sections.pos().x() + sec_protected.pos().x() - DISTANCE / 2, sections.pos().y(), sections.pos().x()+ sec_protected.pos().x() - DISTANCE / 2, sections.pos().y() + sections.boundingRect().height());painter->drawLine(sections.pos().x() + sec_private.pos().x() - DISTANCE / 2, sections.pos().y(),sections.pos().x() + sec_private.pos().x() - DISTANCE / 2, sections.pos().y()+ sections.boundingRect().height());
VFields
items std::vector< std::vector< VBase* > >row_heights std::vector< int >column_widths std::vector< int >size_x intsize_y int
removeAllItems
int y = 0; y < size_y; ++y
int x = 0; x < size_x; ++x
items[y][x]
delete items[y][x];items[y][x] = NULL;
updateRepresentation();
VGrid parentVBase*
setClientSize(5,5);
~VGrid
removeAllItems();setXY new_x
intnew_y
int
removeAllItems();column_widths.clear();row_heights.clear();
new_x <= 0 || new_y <= 0
size_x = 0;size_y = 0;
size_x = new_x;size_y = new_y;column_widths.resize(size_x);row_heights.resize(size_y);items.resize(size_y);
int y = 0; y<size_y; ++y
items[y].resize(size_x);
int x = 0; x<size_x; ++x
items[y][x] = NULL;
updateRepresentation();
getX
return size_x;
getY
return size_y;
setItem xint
y int
item VBase*
removeItem(x, y);x>= 0 && x < size_x && y >= 0 && y < size_y
items[y][x] = item;updateRepresentation();
removeItem xint
y int
x>= 0 && x < size_x && y >= 0 && y < size_y && items[y][x]
delete items[y][x];items[y][x] = NULL;updateRepresentation();
updateRepresentation
int x = 0; x < size_x; ++x
column_widths[x] = 0;
int y = 0; y < size_y; ++y
row_heights[y] = 0;
int y = 0; y < size_y; ++y
int x = 0; x < size_x; ++x
items[y][x]
row_heights[y] < items[y][x]->boundingRect().height()
row_heights[y] = items[y][x]->boundingRect().height();
column_widths[x] < items[y][x]->boundingRect().width()
column_widths[x] = items[y][x]->boundingRect().width();
int total_width = 0;int total_height = 0;
int x = 0; x < size_x; ++x
total_width += column_widths[x];
int y = 0; y < size_y; ++y
total_height += row_heights[y];
setClientSize(total_width, total_height);total_height = 0;
int y = 0; y < size_y; ++y
total_width = 0;
int x = 0; x < size_x; ++x
items[y][x]
items[y][x]->setPos( getPadding() + total_width + ceil(( column_widths[x] - items[y][x]->boundingRect().width())/2) ,getPadding() + total_height + ceil(( row_heights[y] - items[y][x]->boundingRect().height())/2) ) ;
total_width += column_widths[x];
total_height += row_heights[y];
VBox::updateRepresentation();
VGrid
ifelse CIfElse*icon IfElseIconheader VBoxed<VText, CText>body VLinear<VSequence<CStatement, VStatement> >then_branch VSequence<CStatement, VStatement>_branch _branch
VIfElse parentVBase*
ifelse CIfElse*
setEventHandler(HIfElse::getInstance());then_branch.setStyle(SIfElse::getThenStyle());else_branch.setStyle(SIfElse::getElseStyle());body.setStyle(SInvisible::getNormalStyle());setStyle(SIfElse::getNormalStyle());header.setStyle(SIfElse::getHeaderStyle());body.setOptions(false, false, 15);body.addItem(&then_branch);body.addItem(&else_branch);setClient(&body);setHeader(&header);setIcon(&icon);setFocusProxy(&then_branch);
switchFocus
cursor.pos = 0;then_branch.HasFocusInHierarchy()
else_branch.size() < 1
CSequence<CStatement>* seq = dynamic_cast<CSequence<CStatement>*> (else_branch.getConstruct());seq->insertNewAfter<CStatement> ();focus(&(*seq)[0]->getText());qDebug() << "Scheduled for focusing";
else_branch[0]->getText().setFocus();
then_branch[0]->getText().setFocus();
getThen
return then_branch;
getElse
returnelse_branch;
VIfElse
items std::vector<V*>distance intvertical booljustified bool
VLinear parentVBase*
setFlag(ItemIsMovable, false);setStyle(SInvisible::getNormalStyle());updateRepresentation();
size
return items.size();
removeAllItems
items.clear();
setOptions verticalbool
justified bool
distance int
this->vertical = vertical;this->justified = justified;this->distance = distance;updateRepresentation();
addItem new_itemV*
new_item
items.push_back(new_item);
updateRepresentation();
updateRepresentation
int max_height = 0;int max_width = 0;int total_width = 0;int total_height = 0;
size_t i = 0; i < items.size(); ++i
max_height < items[i]->boundingRect().height()
max_height = items[i]->boundingRect().height();
max_width < items[i]->boundingRect().width()
max_width = items[i]->boundingRect().width();
total_width += items[i]->boundingRect().width() + distance;total_height += items[i]->boundingRect().height() + distance;
total_width -= distance;total_height -= distance;
vertical
setClientSize(max_width, total_height); setClientSize(total_width, max_height);
int total = 0;
size_t i = 0; i < items.size(); ++i
int x_offset = 0;int y_offset = 0;
vertical
justified
x_offset = (max_width - items[i]->boundingRect().width()) / 2;
items[i]->setPos(getPadding() + x_offset, getPadding() + total);total += items[i]->boundingRect().height() + distance;
justified
y_offset = (max_height - items[i]->boundingRect().height()) / 2;
items[i]->setPos(getPadding() + total, getPadding() + y_offset);total += items[i]->boundingRect().width() + distance;
VBox::updateRepresentation();
VLinear
loop CLoop*icon LoopIconheader VBoxed<VText,CText>body VSequence<CStatement, VStatement>
VLoop parentVBase*
loop CLoop*
header.setStyle(SLoop::getHeaderStyle());setStyle(SLoop::getNormalStyle());setClient(&body);setHeader(&header);setIcon(&icon);setFocusProxy( &body );
paint painterQPainter*
option const QStyleOptionGraphicsItem*
widget QWidget*
VStatement::paint(painter, option, widget);QPoint t[3];painter->setBrush(getStyle()->border.color());painter->setPen(Qt::NoPen);const int RIGHT_OFFSET = 1;
int i = bounding_rect.bottom() - getClientHeight(); i < bounding_rect.bottom() - getPadding(); i += 5* TRIANGLE_SIDE
t[0] = QPoint(RIGHT_OFFSET, i);t[1] = QPoint(+TRIANGLE_SIDE / 2 + RIGHT_OFFSET, i);t[2] = QPoint(RIGHT_OFFSET, i + 2 * TRIANGLE_SIDE);painter->drawPolygon(t, 3);
int i = bounding_rect.left() + 2 * getPadding(); i < bounding_rect.right() - getPadding(); i += 5* TRIANGLE_SIDE
t[0] = QPoint(i, bounding_rect.bottom());t[1] = QPoint(i, bounding_rect.bottom() - TRIANGLE_SIDE / 2);t[2] = QPoint(i + 2 * TRIANGLE_SIDE, bounding_rect.bottom());painter->drawPolygon(t, 3);
int i = bounding_rect.bottom() - 2 * getPadding(); i > bounding_rect.bottom() - getClientHeight(); i -= 5* TRIANGLE_SIDE
t[0] = QPoint(bounding_rect.right() - TRIANGLE_SIDE / 2, i);t[1] = QPoint(bounding_rect.right(), i);t[2] = QPoint(bounding_rect.right(), i - 2 * TRIANGLE_SIDE);painter->drawPolygon(t, 3);
int i = bounding_rect.right() - 2 * getPadding(); i > bounding_rect.left() + 2 * getPadding()+ header.boundingRect().width(); i -= 5 * TRIANGLE_SIDE
t[0] = QPoint(i, bounding_rect.bottom() - getClientHeight() - header.boundingRect().height() / 2 - 2* getPadding() + TRIANGLE_SIDE / 2);t[1] = QPoint(i, bounding_rect.bottom() - getClientHeight() - header.boundingRect().height() / 2 - 2* getPadding());t[2] = QPoint(i - 2 * TRIANGLE_SIDE, bounding_rect.bottom() - getClientHeight()- header.boundingRect().height() / 2 - 2 * getPadding());painter->drawPolygon(t, 3);
getBody
return body;
VLoop
method CMethod*header VLinear<VBase>icon MethodIconname VBoxed<VText, CText>statements VSequence<CStatement, VStatement>arguments VSequence<CVariableDeclaration, VMethodArgument>
VMethod parentVBase*
method CMethod*
arguments.setSequenceOptions(false, 5);name.item.setStyle(SMethodName::getNormalStyle());name.setStyle(SMethod::getTitleStyle());arguments.setStyle(SMethod::getTitleStyle());setStyle(SMethod::getNormalStyle());header.setOptions(false, true, 15);header.addItem(&name);header.addItem(&arguments);setClient(&statements);setHeader(&header);setIcon(&icon);
getStatements
return statements;
VMethod
dec CVariableDeclaration*v VLinear<VText>name VTexttype VText
VMethodArgument parentVBase*
dec CVariableDeclaration*
setEventHandler( HMethodArgument::getInstance() );name.setZValue(v.zValue() + 1);type.setZValue(v.zValue() + 1);type.setStyle(SType::getNormalStyle());v.setOptions(true, true, 2);v.addItem(&name);v.addItem(&type);setStyle(SInvisible::getNormalStyle());setClient(&v);
VMethodArgument getName
return name;
getType
return type;
VMethodArgument
mod CModule*classes VSet<CClass, VClass>name VTextbig_name static boolstyle SModule
VModule parentVBase*
mod CModule*
setEventHandler(HModule::getInstance());style.background.setColor( mod_->getColor() );setStyle(&style);setClient(&classes);name.setPos(15, 15);name.setZValue(10);name.setStyle(SModuleName::getNormalStyle());
updateRepresentation
big_name
name.setStyle(SModuleName::getHugeStyle());name.setPos(bounding_rect.width() / 2 - name.boundingRect().width() / 2, bounding_rect.height() / 2- name.boundingRect().height() / 2);
name.setStyle(SModuleName::getNormalStyle());name.setPos(15, 15);
VBox::updateRepresentation();
switchBigNames
big_name = !big_name;
VModule
prompt CPrompt*contents VLinear<VBase>text VTexterrors VLinear <VText>error1 VText*error2 VText*
VPrompt parentVBase*
prompt CPrompt*
setEventHandler(HPrompt::getInstance());setStyle(SPrompt::getNormalStyle());contents.setStyle(SInvisible::getNormalStyle());errors.setStyle(SInvisible::getNormalStyle());errors.setOptions(true, false, 3);contents.setOptions(true, false, 4);contents.addItem(&text);contents.addItem(&errors);setClient(&contents);setZValue(6);
focus
text.setFocus();text.visualizationChanged();
updateRepresentation
errors.size() > 0 && prompt->getError1().getText().isEmpty()
errors.removeAllItems();errors.setStyle(SInvisible::getNormalStyle());delete error1;error1 = NULL;delete error2;error2 = NULL;
errors.size() == 0 && !prompt->getError1().getText().isEmpty()
error1 = new VText(&errors, &prompt->getError1());errors.addItem(error1);error2 = new VText(&errors, &prompt->getError2());errors.addItem(error2);errors.setStyle(SPrompt::getErrorStyle());contents.updateRepresentation();
VBox::updateRepresentation();
VPrompt
dec CVariableDeclaration*v VLinear<VText>name VTextcinfo CTextvinfo VText
VRuntimeVariableInfo parentVBase*
dec CVariableDeclaration*
name.setZValue(v.zValue() + 1);vinfo.setStyle(SVarInfo::getNormalStyle());v.setOptions(false, false, 5);v.addItem(&name);v.addItem(&vinfo);setStyle(SInvisible::getNormalStyle());setClient(&v);
getName
return name;
getVInfo
return vinfo;
getCInfo
return cinfo;
VRuntimeVariableInfo
cons CSequence<C>*items std::vector<R*>distance intvertical bool
removeAllItems
size_t i = 0; i < items.size(); ++i
delete items[i];items[i] = NULL;
items.clear();
isConstructIdentityChanged
bool ok = items.size() == cons->size();ok
int i = 0; i < items.size(); ++i
ok = ok && items[i]->getConstruct() == (*cons)[i];
return !ok;
VSequence parentVBase*
construct CSequence<C>*
setEventHandler(HSequence::getInstance());setFlag(ItemIsMovable, false);setStyle(SInvisible::getNormalStyle());updateRepresentation();
~VSequence
removeAllItems();
getItems
return items;
size
return items.size();
operator[] iint
return items[i];
setSequenceOptions verticalbool
distance int
this->vertical = vertical;this->distance = distance;updateRepresentation();
updateRepresentation
isConstructIdentityChanged()
removeAllItems();
size_t i = 0; i < cons->size(); ++i
C* item = (*cons)[i];CStatement* st = dynamic_cast<CStatement*> (item);
st
items.push_back((R*) VisFactory::getNewStatementVis(this, st)); items.push_back(new R(this, item));
i == 0
setFocusProxy(*items.begin());
int max_height = 0;int max_width = 0;int total_width = 0;int total_height = 0;
size_t i = 0; i < items.size(); ++i
max_height < items[i]->boundingRect().height()
max_height = items[i]->boundingRect().height();
max_width < items[i]->boundingRect().width()
max_width = items[i]->boundingRect().width();
total_width += items[i]->boundingRect().width() + distance;total_height += items[i]->boundingRect().height() + distance;
total_width -= distance;total_height -= distance;
vertical
setClientSize(max_width, total_height); setClientSize(total_width, max_height);
int total = 0;
size_t i = 0; i < items.size(); ++i
vertical
items[i]->setPos(getPadding(), getPadding() + total);total += items[i]->boundingRect().height() + distance;
items[i]->setPos(getPadding() + total, getPadding());total += items[i]->boundingRect().width() + distance;
VBox::updateRepresentation();
VSequence
cons CSet<C>*items std::vector<R*>distance int
removeAllItems
size_t i = 0; i < items.size(); ++i
delete items[i];items[i] = NULL;
items.clear();
VSet parentVBase*
construct CSet<C>*
setFlag(ItemIsMovable, false);setStyle(SInvisible::getNormalStyle());updateRepresentation();
~VSet
removeAllItems();
updateRepresentation
items.size() != cons->size()
removeAllItems();int current_width = 0;int current_height = 0;int biggest_height = 0;
size_t i = 0; i < cons->size(); ++i
R* rep = new R(this, (*cons)[i]);items.push_back( rep );rep->setPos(getPadding() + current_width, getPadding());Position* p = dynamic_cast< Position* > ( (*cons)[i] );
p && p->isAutoPlaced() == false
rep->setPos(p->getX(), p->getY() );int width_to_add = p->getX() + rep->boundingRect().width() - current_width;
width_to_add >0
current_width += width_to_add;
rep->setPos(getPadding() + current_width, getPadding() + current_height);current_width += rep->boundingRect().width();
rep->y() + rep->boundingRect().height() > biggest_height
biggest_height = rep->y() + rep->boundingRect().height();
i>0 && i%3 == 0
current_height = biggest_height;current_width = 0;
int min_x = 0;int max_x = 0;int min_y = 0;int max_y = 0;
items.size() > 0
min_x = items[0]->pos().x();max_x = items[0]->boundingRect().width() + min_x;min_y = items[0]->pos().y();max_y = items[0]->boundingRect().height() + max_y;
size_t i = 0; i < items.size(); ++i
min_x > items[i]->pos().x()
min_x = items[i]->pos().x();
min_y > items[i]->pos().y()
min_y = items[i]->pos().y();
max_x < items[i]->pos().x() + items[i]->boundingRect().width()
max_x = items[i]->pos().x() + items[i]->boundingRect().width();
max_y < items[i]->pos().y() + items[i]->boundingRect().height()
max_y = items[i]->pos().y() + items[i]->boundingRect().height();
setClientSize(max_x - getPadding(), max_y - getPadding());VBox::updateRepresentation();
VSet
VSpacer parentVBase*
bounding_rect.setCoords(0,0,0,0);
updateRepresentation
paint QPainter*QStyleOptionGraphicsItem*
constQWidget*
setSize widthint
height int
bounding_rect.setCoords(0,0,width,height);
VSpacer
method_seq VLinear<VLinear<VBase> >cons_name CTextvis_name VBoxed<VText, CText>methods std::list<VMethod*>spacers std::list<VSpacer*>last_vars VLinear<VBase>*
clearAll
std::list<VMethod*>::iterator it = methods.begin(); it != methods.end(); ++it
delete (*it);
methods.clear();last_vars = NULL;
highlightStatement VSequence<CStatementbegin
VStatement>&count int
int i = 0; i < begin.size(); ++i
VLoop* loop = dynamic_cast<VLoop*> (begin[i]);loop
count = highlightStatement(loop->getBody(), count);continue;
VIfElse* ifelse = dynamic_cast<VIfElse*> (begin[i]);ifelse
count = highlightStatement(ifelse->getThen(), count);count = highlightStatement(ifelse->getElse(), count);continue;
count == 0
begin[i]->setStyle(SStackTrace::getCallStatementStyle());
--count;
return count;
VStackTrace parentVBase*
setStyle(SStackTrace::getNormalStyle());cons_name.setText("Stack Trace 1");method_seq.setOptions(false, false, 30);setClient(&method_seq);setHeader(&vis_name);
~VStackTrace
clearAll();
addMethod methodCMethod*
height int
highlight_line int
VLinear<VBase>* col = new VLinear<VBase> (&method_seq);col->setOptions(true, false, 10);VMethod* vm = new VMethod(col, method);VSpacer* sp = new VSpacer(col);VLinear<VBase>* vars = new VLinear<VBase> (col);vars->setOptions(true, false, 2);last_vars = vars;
highlight_line >= 0
highlightStatement(vm->getStatements(), highlight_line);
sp->setSize(10, height);vm->setStyle(SMethod::getStackTraceStyle());col->addItem(sp);col->addItem(vars);col->addItem(vm);method_seq.addItem(col);updateRepresentation();
addVarInfo varCVariableDeclaration*
info QString
last_vars
last_vars->setStyle(SMethod::getTitleStyle());VRuntimeVariableInfo* vi = new VRuntimeVariableInfo(last_vars, var);vi->getCInfo().setText(info);last_vars->addItem(vi);
VStackTrace
statement CStatement*text VText
VStatement parentVBase*
statement CStatement*
setEventHandler( HStatement::getInstance() );setStyle(SInvisible::getNormalStyle());setClient(&text);setFocusProxy(&text);
getText
return text;
VStatement
text CText*cursor_x int2 static const int EXTRA_TEXT_SPACE =style SText*default_style static SText
VText parentVBase*
text CText*
setEventHandler(HText::getInstance());setFlag(ItemIsMovable);setFlag(ItemIsFocusable);setZValue(5);updateRepresentation();
paint painterQPainter*
option const QStyleOptionGraphicsItem*
widget QWidget*
painter->setFont(style->font);painter->setPen( style->pen );painter->drawText(bounding_rect, Qt::TextExpandTabs, text->getText());
hasFocus()
painter->setPen( QPen(Qt::black, 2) );painter->drawLine(cursor_x, bounding_rect.top(), cursor_x, bounding_rect.bottom());
painter->setFont( QFont() );
updateRepresentation
QFont font("Arial", 12, style->font.weight(), style->font.italic() );font.setPixelSize(style->font.pixelSize());QString msg = text->getText();
msg.length() == 0
msg = " ";
QFontMetrics fmet(font);QSize s = fmet.size(Qt::TextExpandTabs, msg);bounding_rect.setWidth(s.width() + EXTRA_TEXT_SPACE);bounding_rect.setHeight(s.height());bounding_rect.moveTop(0);bounding_rect.moveLeft(0);
hasFocus()
QString cursorleft = msg.left(cursor.pos);cursor_x = fmet.size(Qt::TextExpandTabs, cursorleft).width();
setStyle styleSText*
this->style = style;updateRepresentation();
VText
vis
getNewStatementVis parentVBase*
statement CStatement*
CLoop* cl = dynamic_cast<CLoop*> (statement);cl
return new VLoop(parent, cl); CIfElse* cie = dynamic_cast<CIfElse*> (statement);cie
return new VIfElse(parent, cie) ; return new VStatement(parent, statement);
VisFactory
vis_helpers
Envision
Figure 11: The constructs module of Envision. Classes here implement the logical model ofprogramming entities such as classes, methods, statements etc. Zoom-in to see more detail.
constructors; getters and setters appear to the right; auxiliary methods, if any, appear in the lowerright corner.
We can see how one can get an overview of an entire module or even the entire application byzooming out. Navigating around the application space is currently achieved by zooming in andout, using the scroll bars or using the arrow keys on the keyboard.
In our experience of visualizing Envision’s source code, one of the most useful features was to seemethods or classes side by side.
3.5 Case study: call stack visualization
This style of software representation could offer interesting features in terms or error reporting anddebugging. We explored a sample call stack visualization presented in figure 12. The methods fromthe stack are arranged from left to right in the order in which they were called. The highlightedline(orange) in each method is where the call to the next one occurs. Vertically the methods arealigned to this line to make it easier to trace. Information about the run-time argument valuesappears above each method. A useful feature here is the juxtaposition of all relevant methods onone screen. This eliminates the need to switch between different files or classes as is the case inmodern IDEs.
4 Discussion
As part of this feasibility study we developed a mock-up version of Envision which was presentedin the previous section. It focuses only on the core concepts of visualization and user input. Herewe discuss our experiences with the application and comment on how it compares to traditionalIDEs.
It is important to note that the mock-up Envision application can not be used to develop soft-
19
Figure 12: A mock-up stack-trace from the execution of Envision. A vector graphic could not beproduced.
ware. Therefore all the comparisons in this section are based on preliminary results and projectedfeatures. This introspective evaluation is only an initial step. Proper quantitative studies arerequired to objectively asses the performance of our approach.
4.1 Implementation of the visualization principles
First we reflect on how the current concept of Envision implements the design principles outlinedin section 3.2.
4.1.1 General-purpose
Envision is similar to a wrapper around an OOP language like C++, Java or C#. It retains thesame object model and relationship between entities. It also inherits the general-purpose natureof those languages.
4.1.2 Efficient
We believe the proposed input methods which are a core part of Envision have the potential tobe even more efficient that textual programming. This is evidently the case with the simple HelloWorld example presented earlier. To measure the efficiency of our approach on larger real-worldprograms, it would be first necessary to implement more features.
4.1.3 Fast
The current mock-up application is performing snappily even at more demanding tasks such asrendering of the entire Envision code base. Moreover this is done entirely in software using asingle thread on a mid-range laptop. Therefore at its current stage of development Envision
20
meets the performance goal. To accommodate for future expansions we plan to employ renderingon dedicated graphics hardware.
4.1.4 Intuitive
Our system is based on OOP. So far the main visualization techniques are encapsulating entitiesinto boxes and showing a tree hierarchy of the different entities. The former is natural when itcomes to objects and data structures - enclosing them with a frame makes them more concreteand tangible. The latter is inherent in the structure of software written in the OOP paradigm.We think this contributes to the intuitiveness of Envision.
4.1.5 Flexible
We have shown that Envision is capable of covering the full spectrum of abstractions for a softwareapplication. It can show the entire application at once, outlining the relationship between differentmodules. Using the zoom feature it is possible to focus on a single module, class or method. Atthe method level one can directly observe the execution instructions of the program. This shouldprovide enough flexibility for practically any task.
4.1.6 Focused
Envision’s interface is minimal, there are no menus, toolbars or multiple visible tools. Only sourcecode fragments are shown and arranged in the way the programmer specifies. Common tasks canbe performed directly using the prompt. We find this more efficient both in terms of speed andutilizing screen real estate.
4.1.7 Appropriate
We do not limit our approach to pure pictorial visualizations. The integration of text and visualsin Envision aims to match a concept with a natural representation. Our system is flexible andcan provide for many different types of visualizations. A more objective evaluation and long-termexperimentation is needed to determine which visualization styles are suited for what softwarefragments.
4.1.8 Self-sufficient
The current mock-up application just showcases some interesting aspects of the Envision concept.Much more work is needed before the application can be used to design programs. This is discussedfurther in section 5.
4.1.9 Varied
Presently Envision is rendered entirely using zoom-able vector graphics in full 32-bit color. Variouseffects such as anti-aliasing, font smoothing and translucency are also used. Our visualization stylesinclude different shapes, colors and borders and as representation entities we use boxes, gradients,symbols, icons and text. Semantics are described by both the look of an object as well as byits position. As one can see we are already utilizing a wide variety of visual objects and plan toexpand this further.
21
4.1.10 Friendly
Our experience with Envision’s current interface is positive. However there are many plannedfeatures that we need to implement before the application is functional. Since friendliness is avery subjective quality, only a large-scale experiment with programmers can help make conclusions.
4.2 Comparison to traditional programming environments
Here we evaluate how Envision’s approach compares to one of the most popular IDEs - Eclipse.Eclipse is a mature software development platform with a complete set of features and numerousextensions contributed by third parties. It is actively supported by both industrial organizationsand by the open source community. Therefore a direct comparison between Envision and Eclipseat this time is unrealistic. Rather we will limit ourselves to the code editing and navigatingfunctions. Furthermore we will only consider the standard Eclipse installation that does notinclude any third-party plug-ins.
4.2.1 Productivity
Productivity here refers to the speed at which one can write code.
In Eclipse one has to type the entire structure of their program manually. A few exceptions arethe use of the code completion feature and code wizards for e.g. new classes.
In Envision the programmer creates structure by issuing commands. These commands are contextsensitive and have a light syntax. In essence what the programmer types is not directly thesoftware structure but is first interpreted by the environment based on the context to determinewhat programming fragment should be created. This concept is similar to sloppy programming[24, 17, 25]. This separation can be very powerful. For example when typing, the user can use acompact syntax similar to scripting or functional languages, while the result can be a standardOOP structure for languages like Java. We plan to enhance the command typing mechanism toaid the programmer in a way similar to code completion. This will further make it easier to quicklycreate complicated program structures.
We feel that Envision will enable higher productivity compared to Eclipse as the input mechanismswe propose become more mature.
4.2.2 Readability
Eclipse provides a number of readability improvements over plain text file editors. These includesyntax coloring, code elision and automatic formatting. The underlying representation however,remains purely textual.
Envision on the other hand shows the entire program structure in one consistent tree hierarchy.It produces images which have a minimal number of distracting features. Common semantics arerepresented visually rather than via syntax and keywords. Only the core logic of the applicationappears in textual form. There is no need for formatting since code structure is automatically andexplicitly visualized by the system.
As a result, from a cognitive point of view, we believe our approach will improve readability.Graphically expressed features will be processed by the visual cognitive system. This is a veryquick parallel process that is largely unconscious. Thus more capacity is left for deeper cognitiveprocesses which are needed to process application-specific logic expressed as text.
22
4.2.3 Navigation
In Eclipse one navigates between different code fragments by switching to different tabs. Optionallyone can search for a specific keyword, entity definition or object reference. It is also possible toclick on an identifier in the editor window and navigate to its definition or uses.
These mechanisms are extremely useful when the programmer is looking for specific information.Therefore we are planning to include such features.
Additionally Envision allows the programmer to navigate code by looking at the software structure.Zooming out, one can see how different methods, classes and modules relate to each other. Thisis very useful when exploring the software for the first time. We believe that developers can usethis feature to get more familiar with an unknown application faster.
4.2.4 Maintainability (Viscosity)
Maintainability here refers directly to one of the more severe problems identified by Green andPetre in [19] - resistance to local change. In their original analysis they concluded that visualprogramming languages reduce the user’s performance when local modifications are necessary toexisting programs. They found that such tasks are done several times faster in traditional textualIDEs.
On this point a textual IDE such as Eclipse facilitates high performance.
Envision aims to achieve similar results. All textual fields visible on the screen can be directlymodified. Since core logic is expressed as textual instructions they should allow for equally fastchanges. One problem we experienced with the mock-up application is that each time there wasa change to a program fragment we needed to manually adjust the positioning of surroundingentities. This is currently a hindrance in achieving low viscosity and we plan to include automaticpositioning features to alleviate this problem.
4.2.5 Teaching
While Eclipse is an extremely powerful platform for software development, it has little to offerto novice programmers. We have experience in courses where non-programmers were learning toprogram in Java using Eclipse. Mistakes often made by beginners include misplacing of semicolons,confusing the scope of an identifier, using the wrong kind of parenthesis or brace and bad codeformatting.
Since Envision takes care of structure internally all of the above problems disappear. For smallclassroom examples Envision can be especially useful since the entire application can be visualizedon a single screen.
5 Future work
Envision is still a work in progress. Many core concepts are planned for future development andthe ones discussed here still need additional improvements. Here is a summary of possible futurework:
• Quantitative analysis - Although this study serves to give an initial impression of theEnvision system, it needs to be objectively validated. More information is needed on howexpert programmers will interact with the system. Quantitative studies with developersmust be carried out.
23
• Feature-full prototype - A feature-full prototype can be designed to enable better systemevaluation and experimentation. Such a prototype would also be needed to support studieswith programmers.
• Concept refinement - The visualization and interaction concepts need further improve-ment. In particular the input system requires a more complete implementation that willprovide more insight about its strengths and weaknesses.
• Error reporting - we have barely scratched the surface of how Envision can benefit errorreporting and debugging. More knowledge is needed about how our visual approach canimprove existing practices.
• Information system implementation - We have not yet investigated the informationsystem side of Envision. This track of research and development also presents many chal-lenges: How will semantic versioning work? What content can be linked and how? Whichanalysis techniques can we combine to improve the programming experience? How do wepresent the results of this analysis?
6 Conclusion
In this study we have presented Envision - a combination of an IDE for visual programming and aninformation system. Our contributions include developing the concept of Envision and its designprinciples, implementing a mock-up application to demonstrate its core ideas and comparing itsperformance to a modern text-based IDE - Eclipse. The evaluation of our approach carried outduring this feasibility study is largely positive with some inconclusive results. There is a lot offuture work needed to further develop the concept of Envision and validate its applicability. Westrive to promote visual programming in large scale software development projects. The ultimategoal of Envision is to allow the production of higher-quality software faster.
References
[1] R.N. Shepard. Recognition memory for words, sentences, and pictures1. Journal of VerbalLearning and Verbal Behavior, 6(1):156–163, 1967.
[2] L. Standing. Learning 10000 pictures. The Quarterly Journal of Experimental Psychology,25(2):207–222, 1973.
[3] S. Schiffer and J.H. Frohlich. Visual programming and software engineering with Vista. Visualobject-oriented programming: concepts and environments, pages 199–227, 1995.
[4] B.W. Chang, D. Ungar, and R.B. Smith. Getting close to objects: Object-focused program-ming environments. Visual object-oriented programming: concepts and environments, pages185–198, 1995.
[5] W. Citrin, M. Doherty, and B. Zorn. The design of a completely visual object-orientedprogramming language. Visual Object-Oriented Programming: Concepts and Environments.Prentice-Hall, New York, 1995.
[6] PT Cox, FR Giles, and T. Pietrzykowski. Prograph. Visual Object-Oriented Programming:Concepts and Environments. Prentice-Hall, New York, 1995.
[7] C. Grant. The Visula programming language and environment. In IEEE Symposium on VisualLanguages and Human-Centric Computing, 2006. VL/HCC 2006, pages 203–206, 2006.
24
[8] E. Baroth and C. Hartsough. Visual programming in the real world. In Visual object-orientedprogramming, page 42. Manning Publications Co., 1995.
[9] R. DeLine, A. Khella, M. Czerwinski, and G. Robertson. Towards understanding programsthrough wear-based filtering. In Proceedings of the 2005 ACM symposium on Software visu-alization, pages 183–192. ACM, 2005.
[10] R. DeLine, M. Czerwinski, and G. Robertson. Easing program comprehension by sharingnavigation data. 2005.
[11] M. Cherubini, G. Venolia, R. DeLine, and A.J. Ko. Let’s go to the whiteboard: how andwhy software developers use drawings. In Proceedings of the SIGCHI conference on Humanfactors in computing systems, page 566. ACM, 2007.
[12] R. DeLine. Staying oriented with software terrain maps. In International Conference onDistributed Multimedia Systems. Citeseer.
[13] R. DeLine, M. Czerwinski, B. Meyers, G. Venolia, S. Drucker, and G. Robertson. Codethumbnails: Using spatial memory to navigate source code. 2006.
[14] M.A. Storey, C. Best, J. Michaud, D. Rayside, M. Litoiu, and M. Musen. SHriMP views:an interactive environment for information visualization and navigation. In CHI’02 extendedabstracts on Human factors in computing systems, page 521. ACM, 2002.
[15] A. Bragdon, R. Zeleznik, S.P. Reiss, S. Karumuri, W. Cheung, J. Kaplan, C. Coleman,F. Adeputra, and J.J. LaViola Jr. Code bubbles: a working set-based interface for code un-derstanding and maintenance. In Proceedings of the 28th international conference on Humanfactors in computing systems, pages 2503–2512. ACM, 2010.
[16] A. Bragdon, S.P. Reiss, R. Zeleznik, S. Karumuri, W. Cheung, J. Kaplan, C. Coleman,F. Adeputra, and J.J. LaViola Jr. Code Bubbles: Rethinking the user interface paradigm ofintegrated development environments. In Proceedings of the 32nd ACM/IEEE InternationalConference on Software Engineering-Volume 1, pages 455–464. ACM, 2010.
[17] G. Little and R.C. Miller. Keyword programming in java. Automated Software Engineering,16(1):37–71, 2009.
[18] K.N. Whitley. Visual programming languages and the empirical evidence for and against.Journal of Visual Languages and Computing, 8(1):109–142, 1997.
[19] T.R.G. Green and M. Petre. Usability Analysis of Visual Programming Environments: A’Cognitive Dimensions’ Framework. Journal of Visual Languages and Computing, 7(2):131–174, 1996.
[20] M. Petre. Mental imagery and software visualization in high-performance software develop-ment teams. Journal of Visual Languages & Computing, 2010.
[21] K.N. Whitley and A.F. Blackwell. Visual programming in the wild: A survey of LabVIEWprogrammers. Journal of Visual Languages & Computing, 12(4):435–472, 2001.
[22] A. Cimino, F. Longo, and G. Mirabelli. A General Simulation Framework for Supply ChainModeling: State of the Art and Case Study. Arxiv preprint arXiv:1004.3271, 2010.
[23] S. Bangsow. Manufacturing Simulation with Plant Simulation and Simtalk: Usage and Pro-gramming with Examples and Solutions. Springer Verlag, 2010.
[24] G. Little and R.C. Miller. Translating keyword commands into executable code. In Proceedingsof the 19th annual ACM symposium on User interface software and technology, page 144.ACM, 2006.
25