public FileView(Composite parent) {
		this.canvas = new Canvas(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.NO_BACKGROUND);
		
		canvas.addMouseWheelListener(new MouseWheelListener() {
			public void mouseScrolled(MouseEvent event) {
				ScrollBar bar = canvas.getVerticalBar();
				bar.setSelection(bar.getSelection() - event.count * 50);
			}
		});
		
		canvas.addControlListener(new ControlAdapter() {
			public void controlResized(ControlEvent event) {
				setBounds();
				canvas.redraw();
			}
		});
		
		canvas.addMouseListener(new MouseAdapter() {
			public void mouseUp(MouseEvent event) {
				int line = (canvas.getVerticalBar().getSelection() + event.y) / lineHeight;
				
				TreeItem treeItem = activeModel.getTreeItemAtRow(line);
				if(treeItem != null) {
					if(event.x + canvas.getHorizontalBar().getSelection() < 20) {
						if(treeItem.hasChildren()) {
							treeItem.toggleExpanded();
						}
						setBounds();
						canvas.redraw();
					}
				}
			}
		});
		
		canvas.getHorizontalBar().addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				canvas.redraw();
			}
		});
		
		canvas.getVerticalBar().addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				int diff = verticalOffset - canvas.getVerticalBar().getSelection();
			
				canvas.scroll(0, diff, 0, 0, canvas.getBounds().width, canvas.getBounds().height, true);
				
				verticalOffset = canvas.getVerticalBar().getSelection();
			}
		});
		
		canvas.addPaintListener(new PaintListener() {
			public void paintControl(PaintEvent event) {
				Image buffer = new Image(Display.getCurrent(), canvas.getBounds());
				GC gc = new GC(buffer);
				gc.setAntialias(SWT.ON);
				
				gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
				
				int top = verticalOffset;
				int bottom = verticalOffset + canvas.getClientArea().height;
				
				Transform transform = new Transform(Display.getCurrent());
				transform.translate(-canvas.getHorizontalBar().getSelection(), 0);
				gc.setTransform(transform);
				
				int offsetY = -(top % lineHeight);
				
				for(
					TreeItem treeItem = activeModel.getTreeItemAtRow(top / lineHeight);
					treeItem != null && treeItem.getRow() * lineHeight <= bottom;
					treeItem = treeItem.getNext()
				) {
					int indent = 0;
					if(treeItem.hasChildren() || treeItem.getLevel() > 0) {
						gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
						indent = 10;
					} else {
						gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
					}
					gc.drawText(treeItem.getText(), 20 + indent, offsetY + 2);
					
					gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
					
					if(treeItem.hasChildren()) {
						Rectangle expander = new Rectangle(3, offsetY + 4, 4, 8);
						
						if(treeItem.isExpanded()) {
							gc.drawLine(expander.x, expander.y + 2, expander.x + 10, expander.y + 2);
							gc.drawLine(expander.x, expander.y + 2, expander.x + 5, expander.y + 7);
							gc.drawLine(expander.x + 10, expander.y + 2, expander.x + 5, expander.y + 7);
						} else {
							gc.drawLine(expander.x + 2, expander.y, expander.x + 2, expander.y + 10);
							gc.drawLine(expander.x + 2, expander.y, expander.x + 7, expander.y + 5);
							gc.drawLine(expander.x + 2, expander.y + 10, expander.x + 7, expander.y + 5);
						}
					}
					
					offsetY += lineHeight;
				}
				
				event.gc.drawImage(buffer, 0, 0);
				buffer.dispose();
				transform.dispose();
			}
		});
	}