a feasibility study for a general-purpose visual ... · research in computer science ii spring 2010...

26
Research in Computer Science II Spring 2010 A feasibility study for a general-purpose visual programming system Dimitar Asenov Supervisor: Peter M¨ uller 19 th July, 2010

Upload: vuque

Post on 15-Jul-2018

216 views

Category:

Documents


0 download

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(&sections);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

[25] G. Little, T.A. Lau, A. Cypher, J. Lin, E.M. Haber, and E. Kandogan. Koala: capture,share, automate, personalize business processes on the web. In Proceedings of the SIGCHIconference on Human factors in computing systems, page 946. ACM, 2007.

26