Sample

Schnappinger/aoi/artofillusion.animation.ActorEditorWindow

Human rating uses the original dataset scale.

Human2.85
Lines479

Scores

MethodScoreScaleDataset rank
(0–100)
Posnett00–1; higher is more readable
9.7Δ 9.4
Scalabrino0.6310–1; higher is more readable
26.7Δ 7.6
Dorn0.0020–1; higher is more readable
12.2Δ 6.9
Mi0.2990–1; higher is more readable
20.5Δ 1.3
LLOC263Logical lines; fewer is more readable
8.9Δ 10.2
DeepSeek V4 Pro11.670–20; mean of three runs
13.9Δ 5.3
GPT-6.1 Sol150–20; mean of three runs
25.7Δ 6.6
BTTF0.1210–1; higher is more readable
4.3Δ 14.9
Human2.851–4; original rating
19.1

Views

Source code

/* Copyright (C) 2002-2006 by Peter Eastman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ package artofillusion.animation; import artofillusion.*; import artofillusion.animation.Actor.*; import artofillusion.math.*; import artofillusion.object.*; import artofillusion.ui.*; import buoy.event.*; import buoy.widget.*; import javax.swing.table.*; import javax.swing.*; import java.awt.*; /** The ActorEditorWindow class represents the window for editing Actor objects. */ public class ActorEditorWindow extends BDialog { private Actor theObject, oldObject; private ObjectInfo objInfo; private EditingWindow theWindow; private BList gestureList; private BTable currentPoseTable; private CurrentPoseTableModel tableModel; private BButton addButton, removeButton, saveButton, extractButton; private BButton editButton, renameButton, copyButton, deleteButton; private BButton okButton, cancelButton; private ActionProcessor processor; private ActorKeyframe currentPose, key; private ObjectPreviewCanvas preview; private Runnable onClose; private boolean canModifyGestures; /** Display a window for editing a pose of an Actor. If key is null, the Actor's current pose will be edited. Otherwise, the specified keyframe will be edited. */ public ActorEditorWindow(EditingWindow parent, ObjectInfo info, Actor obj, ActorKeyframe key, Runnable cb) { super(parent.getFrame(), (key == null ? info.getName() : Translate.text("editKeyframeFor", info.getName())), false); objInfo = info; oldObject = obj; theObject = (Actor) obj.duplicate(); theWindow = parent; this.key = key; if (key != null) theObject.applyPoseKeyframe(key); currentPose = (ActorKeyframe) theObject.getPoseKeyframe(); onClose = cb; processor = new ActionProcessor(); canModifyGestures = (info.getObject() == obj); for (int i = currentPose.id.length-1; i >= 0; i--) { int which = theObject.findPoseIndex(currentPose.id[i]); if (which == -1) currentPose.deleteGesture(i); } // Layout the components in the window. FormContainer content = new FormContainer(new double [] {0, 0, 1}, new double [] {1, 0, 0}); setContent(content); content.setDefaultLayout(new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, null, null)); // The list of gestures. content.add(UIUtilities.createScrollingList(gestureList = new BList()), 0, 0, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH)); gestureList.setPreferredVisibleRows(10); for (int i = 0; i < theObject.gestureName.length; i++) gestureList.add(theObject.gestureName[i]); gestureList.setMultipleSelectionEnabled(false); gestureList.addEventLink(SelectionChangedEvent.class, this, "updateComponents"); gestureList.addEventLink(MouseClickedEvent.class, new Object() { void processEvent(MouseClickedEvent ev) { if (ev.getClickCount() == 2) doEdit(); } }); // The buttons for editing them. FormContainer leftPanel = new FormContainer(new double [] {1}, new double [] {0, 0, 0, 0, 0, 1, 0, 0}); content.add(leftPanel, 0, 1); leftPanel.setDefaultLayout(new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.HORIZONTAL, new Insets(2, 2, 2, 2), null)); leftPanel.add(editButton = Translate.button("edit", this, "doEdit"), 0, 1); leftPanel.add(renameButton = Translate.button("rename", this, "doRename"), 0, 2); leftPanel.add(copyButton = Translate.button("duplicate", this, "doDuplicate"), 0, 3); leftPanel.add(deleteButton = Translate.button("delete", this, "doDelete"), 0, 4); leftPanel.add(saveButton = Translate.button("save", "...", this, "doSave"), 0, 6); leftPanel.add(extractButton = Translate.button("extract", "...", this, "doExtract"), 0, 7); // The Add and Remove buttons. ColumnContainer addRemovePanel = new ColumnContainer(); content.add(addRemovePanel, 1, 0); addRemovePanel.setDefaultLayout(new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.HORIZONTAL, new Insets(2, 2, 2, 2), null)); addRemovePanel.add(addButton = Translate.button("add", ">>", this, "doAdd")); addRemovePanel.add(removeButton = new BButton("<< "+Translate.text("button.remove"))); removeButton.addEventLink(CommandEvent.class, this, "doRemove"); // The current pose. tableModel = new CurrentPoseTableModel(); currentPoseTable = new BTable(tableModel); currentPoseTable.setMultipleSelectionEnabled(false); currentPoseTable.addEventLink(SelectionChangedEvent.class, this, "updateComponents"); TableColumn column = ((JTable) currentPoseTable.getComponent()).getColumnModel().getColumn(1); column.setCellEditor(new ValueEditor()); ValueRenderer renderer = new ValueRenderer(); column.setCellRenderer(renderer); column.setMinWidth(renderer.getPreferredSize().width); column.setMaxWidth(renderer.getPreferredSize().width); ((JTable) currentPoseTable.getComponent()).setRowHeight(renderer.getPreferredSize().height); BScrollPane tableScrollPane = new BScrollPane(currentPoseTable, BScrollPane.SCROLLBAR_NEVER, BScrollPane.SCROLLBAR_ALWAYS); tableScrollPane.setPreferredViewSize(new Dimension(250, 5*renderer.getPreferredSize().height)); content.add(BOutline.createBevelBorder(tableScrollPane, false), 2, 0); // The object previewer. content.add(preview = new ObjectPreviewCanvas(new ObjectInfo(theObject, new CoordinateSystem(), "")), 1, 1, 2, 1, new LayoutInfo(LayoutInfo.CENTER, LayoutInfo.BOTH, null, null)); preview.setPreferredSize(new Dimension(300, 300)); // The buttons at the bottom. RowContainer bottomPanel = new RowContainer(); content.add(bottomPanel, 0, 2, 3, 1, new LayoutInfo()); bottomPanel.add(okButton = Translate.button("ok", this, "doOk")); bottomPanel.add(cancelButton = Translate.button("cancel", this, "dispose")); pack(); UIUtilities.centerDialog(this, parent.getFrame()); updateComponents(); setVisible(true); } /** Add a new gesture to the current pose. */ private void doAdd() { currentPose.addGesture(theObject.gestureID[gestureList.getSelectedIndex()], 1.0); tableModel.fireTableDataChanged(); updateComponents(); updateDisplay(); } /** Remove a gesture from the current pose. */ private void doRemove() { currentPose.deleteGesture(currentPoseTable.getSelectedRows()[0]); tableModel.fireTableDataChanged(); updateComponents(); updateDisplay(); } /** Save the current pose as a new gesture. */ private void doSave() { BStandardDialog dlg = new BStandardDialog("", Translate.text("savePoseAsGesture"), BStandardDialog.PLAIN); String name = dlg.showInputDialog(this, null, "New Gesture"); if (name == null) return; theObject.addGesture((Gesture) theObject.getWrappedObject().getPoseKeyframe(), name); gestureList.add(name); gestureList.setSelected(gestureList.getItemCount()-1, true); updateComponents(); } /** Save the current pose as a new object. */ private void doExtract() { BStandardDialog dlg = new BStandardDialog("", Translate.text("savePoseAsObject"), BStandardDialog.PLAIN); String name = dlg.showInputDialog(this, null, "Extracted Pose"); if (name == null) return; ObjectInfo info = new ObjectInfo(theObject.getWrappedObject().duplicate(), new CoordinateSystem(new Vec3(), Vec3.vz(), Vec3.vy()), name); info.addTrack(new PositionTrack(info), 0); info.addTrack(new RotationTrack(info), 1); if (theWindow instanceof LayoutWindow) ((LayoutWindow) theWindow).addObject(info, null); else theWindow.getScene().addObject(info, null); theWindow.updateImage(); } /** Edit the currently selected gesture. */ private void doEdit() { if (canModifyGestures) editGesture(gestureList.getSelectedIndex()); } /** Rename a gesture. */ private void doRename() { int which = gestureList.getSelectedIndex(); BStandardDialog dlg = new BStandardDialog("", Translate.text("enterNewNameForGesture"), BStandardDialog.PLAIN); String name = dlg.showInputDialog(this, null, theObject.gestureName[which]); if (name == null) return; theObject.gestureName[which] = name; gestureList.replace(which, theObject.gestureName[which]); gestureList.setSelected(which, true); } /** Duplicate a gesture. */ private void doDuplicate() { int which = gestureList.getSelectedIndex(); BStandardDialog dlg = new BStandardDialog("", Translate.text("enterNameForNewGesture"), BStandardDialog.PLAIN); String name = dlg.showInputDialog(this, null, "Copy of "+theObject.gestureName[which]); if (name == null) return; theObject.addGesture((Gesture) theObject.gesture[which].duplicate(theObject.getWrappedObject()), name); gestureList.add(name); gestureList.setSelected(gestureList.getItemCount()-1, true); updateComponents(); editGesture(gestureList.getItemCount()-1); } /** Delete a gesture. */ private void doDelete() { int which = gestureList.getSelectedIndex(); String options[] = new String [] {Translate.text("Yes"), Translate.text("No")}; int choice = new BStandardDialog("", Translate.text("deleteGesture", theObject.gestureName[which]), BStandardDialog.QUESTION).showOptionDialog(this, options, options[0]); if (choice== 1) return; for (int i = 0; i < currentPose.id.length; i++) if (currentPose.id[i] == theObject.gestureID[which]) { currentPose.deleteGesture(i); i--; updateDisplay(); } theObject.deleteGestureWithID(theObject.gestureID[which]); gestureList.remove(which); tableModel.fireTableDataChanged(); updateComponents(); } /** Save the edits. */ private void doOk() { oldObject.copyObject(theObject); if (key != null) { key.copy(currentPose); theWindow.getScene().applyTracksToObject(objInfo); theWindow.updateImage(); } dispose(); if (onClose != null) onClose.run(); } /** Display a window to let the user edit a gesture. */ private void editGesture(int which) { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); Object3D editObj = theObject.getWrappedObject().duplicate(); editObj.applyPoseKeyframe(theObject.gesture[which]); EditCallback cb = new EditCallback(editObj, theObject.gestureID[which]); ObjectInfo info = objInfo.duplicate(editObj); info.setName(theObject.gestureName[which]); editObj.editGesture(theWindow, info, cb, objInfo); setCursor(Cursor.getDefaultCursor()); } /** Update the status of the buttons and weight field. */ private void updateComponents() { int i, id, selected = gestureList.getSelectedIndex(); if (selected == -1) { addButton.setEnabled(false); editButton.setEnabled(false); renameButton.setEnabled(false); copyButton.setEnabled(false); deleteButton.setEnabled(false); } else { editButton.setEnabled(canModifyGestures); renameButton.setEnabled(canModifyGestures && selected > 0); copyButton.setEnabled(canModifyGestures); deleteButton.setEnabled(canModifyGestures && selected > 0); id = theObject.gestureID[gestureList.getSelectedIndex()]; for (i = 0; i < currentPose.id.length && currentPose.id[i] != id; i++); addButton.setEnabled(selected > 0 && i == currentPose.id.length); } int rows[] = currentPoseTable.getSelectedRows(); removeButton.setEnabled(rows.length > 0); saveButton.setEnabled(canModifyGestures); } /** Reapply the current pose and update the preview. */ private void updateDisplay() { theObject.applyPoseKeyframe(currentPose); preview.objectChanged(); preview.repaint(); } /** This is an inner class which is called when a keyframe has been edited. */ private class EditCallback implements Runnable { public Object3D editObject; public int editID; public EditCallback(Object3D obj, int id) { editObject = obj; editID = id; } public void run() { int which = theObject.findPoseIndex(editID); theObject.getWrappedObject().copyObject(editObject); theObject.gesture[which] = (Gesture) theObject.getWrappedObject().getPoseKeyframe(); // Update the skeletons for all other poses, in case a joint has been added or deleted. Skeleton s = theObject.gesture[which].getSkeleton(); if (s != null) for (int i = 0; i < theObject.gesture.length; i++) { if (i == which) continue; Skeleton olds = theObject.gesture[i].getSkeleton(); Skeleton news = s.duplicate(); Joint joint[] = news.getJoints(); for (int j = 0; j < joint.length; j++) { Joint j2 = olds.getJoint(joint[j].id); if (j2 != null) joint[j].copy(j2); } theObject.gesture[i].setSkeleton(news); } updateDisplay(); } } /** * This is the model for the table describing the current pose. */ private class CurrentPoseTableModel extends AbstractTableModel { public int getRowCount() { return currentPose.getNumGestures(); } public int getColumnCount() { return 2; } public Object getValueAt(int rowIndex, int columnIndex) { if (columnIndex == 0) return theObject.gestureName[theObject.findPoseIndex(currentPose.getGestureID(rowIndex))]; return new Double(currentPose.getGestureWeight(rowIndex)); } public String getColumnName(int column) { return (Translate.text(column == 0 ? "Gesture" : "Weight")); } public boolean isCellEditable(int rowIndex, int columnIndex) { return (columnIndex == 1); } } /** * This is the renderer for values in the Weight column of the table. */ private class ValueRenderer extends BuoyComponent implements TableCellRenderer { private ValueSelector selector; public ValueRenderer() { super(new ValueSelector(0.0, -Double.MAX_VALUE, Double.MAX_VALUE, 0.005)); selector = (ValueSelector) getWidget(); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { selector.setValue(((Double) value).doubleValue()); selector.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground()); return this; } public void validate() { super.validate(); selector.layoutChildren(); } } /** * This is the editor for values in the Weight column of the table. */ private class ValueEditor extends AbstractCellEditor implements TableCellEditor { private ValueSelector selector; private BuoyComponent component; private int currentRow; public ValueEditor() { selector = new ValueSelector(0.0, -Double.MAX_VALUE, Double.MAX_VALUE, 0.005); component = new BuoyComponent(selector) { public void validate() { super.validate(); selector.layoutChildren(); } }; selector.setBackground(((JTable) currentPoseTable.getComponent()).getSelectionBackground()); selector.addEventLink(ValueChangedEvent.class, new Object() { void processEvent() { processor.addEvent(new Runnable() { public void run() { currentPose.weight[currentRow] = selector.getValue(); updateDisplay(); } }); } }); } public Object getCellEditorValue() { return new Double(selector.getValue()); } public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { selector.setValue(((Double) value).doubleValue()); currentRow = row; return component; } } }

Loading feature diagnosis…

Source regions

Feature contributions

Feature contributions

FeatureValueContribution
(log-odds)
Halstead volumeHow much symbolic information the code contains. It combines the total number of operators and values with the number of distinct ones.25224.084−832.395
Source linesThe number of non-empty source lines.479+191.6
Byte entropyHow varied the bytes in the source text are. Repeated bytes give a lower value; a more even mixture gives a higher value.4.936−7.404

Intercept 8.87 + feature contributions = -639.329 (log-odds).
Score = sigmoid(-639.329) = 0.

Score0.631

Feature contributions

FeatureValueContribution
(log-odds)
Comment layout frequencyHow frequently the layout switches between lines containing only comments or whitespace and lines containing code.480−15.959
Indentation frequencyHow rapidly indentation changes from line to line.455+15.001
Number layout frequencyHow rapidly the number of numeric values per line changes through the code.455−10.02
Identifier layout (vertical)How rapidly the visual pattern of identifier characters changes from top to bottom.478.983+6.285
Identifier layout (horizontal)How rapidly the visual pattern of identifier characters changes from left to right. It measures spatial frequency, not the meaning of the names.173.981−3.704
Comment layout (horizontal)How rapidly the visual pattern of comment characters changes from left to right.173.992+2.003
Operator visual areaThe share of the code’s visual area occupied by operators such as +, =, and *.0.105−0.082

Intercept 0.07 + feature contributions = -6.406 (log-odds).
Score = sigmoid(-6.406) = 0.002.

Score0.299
Score263
Run 1

The code has clear, purposeful methods with descriptive names and good separation of concerns, but it suffers from excessive length and dense UI construction. The constructor is very long, packing many layout and component setup steps together, making it hard to follow. Nesting is moderate but some methods like doDelete and the inner EditCallback have multiple concerns and loops that reduce clarity. Action granularity is inconsistent: some lines perform multiple related operations while others are spread out. The overall structure is logical and the code is not tangled, but readability suffers due to verbose UI code, repetitive patterns (e.g., button enabling), and some methods mixing logic with UI updates. The copyright header and comments are helpful, but the class is overloaded with responsibilities (UI setup, event handling, business logic, inner classes for table model/renderer/editor), which adds cognitive load.

Run 2

The code has a clear overall structure with logical method separation, but readability suffers from several issues. The constructor is extremely long and contains the entire UI setup inline, making it difficult to comprehend. There's unnecessary nesting in the constructor, particularly with anonymous inner classes and event handling. Mixing UI code, validation logic, and business logic in methods like doDelete makes intent unclear. Variable names like 'id' and 'which' are ambiguous. Several methods contain multiple actions per line, reducing the ability to follow the flow. The anonymous inner classes (e.g., in ValueEditor) add complexity without clear benefits. Magic numbers (0, 1, 2 in layout coordinates) lack context. Some comments are helpful but don't compensate for the overall density. The code would benefit from extracting UI setup into separate methods, reducing nesting in event handlers, and using more descriptive variable names. While not completely unreadable, it requires careful study to understand.

Run 3

The code demonstrates generally clear structure with logical grouping of methods and UI setup, and follows a consistent naming convention. However, several factors reduce readability: the constructor is very long and mixes UI layout with initialization logic; there are deeply nested inner classes and event handlers; some methods perform multiple actions or have unclear intent (e.g., doAdd, doRemove); and there are confusing patterns like reusing variable names ('i', 'which') with subtle side effects. The use of raw types and mixed Java/Swing APIs adds complexity, while comments are sparse. The code is not unreadable but requires careful navigation and is unnecessarily verbose in places.

Run 1

Code Structure: Cohesive event-handler methods and dedicated inner classes organize responsibilities well, although the constructor mixes extensive layout, initialization, and event wiring. Nesting: Most methods are shallow, but skeleton synchronization and anonymous event callbacks introduce deeper nesting. Clarity of intent: Descriptive method names and useful comments explain most operations; generic variables such as which, s, olds, and news, string-based event links, and an empty-body search loop require extra interpretation. Code length: Individual handlers are generally concise, but the lengthy constructor and repeated dialog and component-update patterns could be extracted into helpers. Action granularity: Most lines perform one action, though assignments embedded in component-add calls combine initialization and registration. Reading flow: Consistent formatting, sectional comments, and logical method grouping support natural reading; long expressions, omitted braces, wildcard imports, and nested anonymous classes occasionally interrupt it.

Run 2

Code Structure: Clearly separated event handlers and dedicated inner classes organize responsibilities, though the large constructor mixes initialization, layout, and event wiring. Nesting: Most methods are shallow, but skeleton synchronization and anonymous event callbacks introduce deeper nesting. Clarity of intent: Descriptive method names and section comments explain the editor's purpose; generic variables such as which, s, olds, and news, direct array manipulation, and string-based event links reduce clarity. Code length: Most handlers are concise, but repetitive UI setup and button-state updates make the class lengthy. Action granularity: Generally one statement per line, although assignments embedded in component additions combine actions, and an empty-body search loop is easy to overlook. Reading flow: Consistent formatting and logical progression from setup to handlers to supporting classes aid navigation. Long expressions, occasionally omitted braces, and nested anonymous classes interrupt otherwise natural flow.

Run 3

Code Structure: Clearly separated event handlers and focused inner classes provide logical organization, although the constructor mixes extensive UI setup with state initialization. Nesting: Most methods are flat, but skeleton synchronization and nested anonymous event callbacks require more effort to follow. Clarity of intent: Descriptive method names and useful comments explain operations well; generic variables such as which, s, olds, and news, plus string-based event bindings, reduce clarity. Code length: Most handlers are concise, but the lengthy constructor and repetitive button configuration could be extracted into helpers. Action granularity: Usually one statement per line, though assignments embedded in component creation and the empty-body search loop obscure individual actions. Reading flow: Consistent formatting and ordering from initialization through handlers to supporting classes make navigation natural; long expressions, omitted braces, and callbacks interrupt that flow.